home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Science⁄Math / Gnuplot 3.5 for Macintosh / SOURCES 3.5 / graph3d_tempo.c < prev    next >
Text File  |  1993-11-08  |  84KB  |  3,026 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: graph3d.c%v 3.50.1.9 1993/08/05 05:38:59 woo Exp $";
  3. #endif
  4.  
  5.  
  6. /* GNUPLOT - graph3d.c */
  7. /*
  8.  * Copyright (C) 1986 - 1993   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted, 
  12.  * provided that the above copyright notice appear in all copies and 
  13.  * that both that copyright notice and this permission notice appear 
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the modified code.  Modifications are to be distributed 
  18.  * as patches to released version.
  19.  *
  20.  * This software is provided "as is" without express or implied warranty.
  21.  *
  22.  *
  23.  * AUTHORS
  24.  *
  25.  *   Original Software:
  26.  *       Gershon Elber and many others.
  27.  *
  28.  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
  29.  * Added user-specified bases for log scaling.
  30.  *
  31.  * There is a mailing list for gnuplot users. Note, however, that the
  32.  * newsgroup 
  33.  *    comp.graphics.gnuplot 
  34.  * is identical to the mailing list (they
  35.  * both carry the same set of messages). We prefer that you read the
  36.  * messages through that newsgroup, to subscribing to the mailing list.
  37.  * (If you can read that newsgroup, and are already on the mailing list,
  38.  * please send a message info-gnuplot-request@dartmouth.edu, asking to be
  39.  * removed from the mailing list.)
  40.  *
  41.  * The address for mailing to list members is
  42.  *       info-gnuplot@dartmouth.edu
  43.  * and for mailing administrative requests is 
  44.  *       info-gnuplot-request@dartmouth.edu
  45.  * The mailing list for bug reports is 
  46.  *       bug-gnuplot@dartmouth.edu
  47.  * The list of those interested in beta-test versions is
  48.  *       info-gnuplot-beta@dartmouth.edu
  49.  */
  50.  
  51. #include <stdio.h>
  52. #include <math.h>
  53. #include <assert.h>
  54. #if !defined(u3b2)
  55. #include <time.h>
  56. #endif
  57. #if !defined(sequent) && !defined(apollo) && !defined(alliant)
  58. #include <limits.h>
  59. #endif
  60. #include "plot.h"
  61. #include "setshow.h"
  62.  
  63. #if defined(DJGPP)||defined(sun386)
  64. #define time_t unsigned long
  65. #endif
  66.  
  67. #if defined(apollo) || defined(sequent) || defined(u3b2) || defined(alliant) || defined(sun386)
  68. #include <sys/types.h> /* typedef long time_t; */
  69. #endif
  70.  
  71. #ifdef THINK_C
  72. #define THINK_P4
  73. #undef THINK_C_3
  74. #define CheckLog(is_log, base_log, x) ((is_log) ? pow(base_log, (x)) : (x))
  75.  
  76. #endif
  77.  
  78.  
  79. /* for preventing moveto while drawing contours */
  80. #ifdef THINK_P4
  81. extern int suppressMove;
  82. #else
  83. int suppressMove = 0;
  84. #endif
  85.  
  86.  
  87. #ifndef AMIGA_SC_6_1
  88. extern char *strcpy(),*strncpy(),*strcat(),*ctime(),*tdate;
  89. #else /* AMIGA_SC_6_1 */
  90. extern char *tdate;
  91. #endif /* AMIGA_SC_6_1 */
  92. #ifdef AMIGA_AC_5
  93. extern time_t dated;
  94. #else
  95. extern time_t dated; /* ,time(); */
  96. #include <time.h>
  97. #endif
  98.  
  99. #ifdef __TURBOC__
  100. #include <stdlib.h>        /* for qsort */
  101. #endif
  102.  
  103. /*
  104.  * hidden_line_type_above, hidden_line_type_below - controls type of lines
  105.  *   for above and below parts of the surface.
  106.  * hidden_no_update - if TRUE lines will be hidden line removed but they
  107.  *   are not assumed to be part of the surface (i.e. grid) and therefore
  108.  *   do not influence the hidings.
  109.  * hidden_active - TRUE if hidden lines are to be removed.
  110.  */
  111. #ifdef THINK_P4
  112. extern int hidden_active;
  113. #else
  114. static int hidden_active = FALSE;
  115. #endif
  116.  
  117. /* LITE defines a restricted memory version for MS-DOS */
  118.  
  119. #ifndef LITE
  120.  
  121. #ifdef THINK_P4
  122. extern int hidden_line_type_above, hidden_line_type_below, hidden_no_update;
  123. #else
  124. static int hidden_line_type_above, hidden_line_type_below, hidden_no_update;
  125. #endif
  126.  
  127. /* We divvy up the figure into the component boxes that make it up, and then
  128.    sort them by the z-value (which is really just an average value).  */
  129. struct pnts{
  130.   int x,y,z;
  131.   int flag;
  132.   long int style_used;    /* acw test */
  133.   int nplot;
  134. };
  135.  
  136. #ifdef THINK_P4
  137. extern int * boxlist;
  138. extern struct pnts * nodes;
  139. #else
  140. static int * boxlist;
  141. static struct pnts * nodes;
  142. #endif
  143.  
  144. /* These variables are used to keep track of the range of x values used in the
  145. line drawing routine.  */
  146. #ifdef THINK_P4
  147. extern long int xmin_hl,xmax_hl;
  148. #else
  149. static long int xmin_hl,xmax_hl;
  150. #endif
  151.  
  152. /* These arrays are used to keep track of the minimum and maximum y values used
  153.    for each X value.  These are only used for drawing the individual boxes that
  154.    make up the 3d figure.  After each box is drawn, the information is copied
  155.    to the bitmap. */
  156. #ifdef THINK_P4
  157. extern short int *ymin_hl, *ymax_hl;
  158. #else
  159. static short int *ymin_hl, *ymax_hl;
  160. #endif
  161.  
  162. /*
  163.  * These numbers are chosen as dividers into the bitmap.
  164.  */
  165. #ifdef THINK_P4
  166. extern short int xfact, yfact;
  167. #else
  168. static short int xfact, yfact;
  169. #endif
  170.  
  171. #define XREDUCE(X) ((X)/xfact)
  172. #define YREDUCE(Y) ((Y)/yfact)
  173.  
  174. /* Bitmap of the screen.  The array for each x value is malloc-ed as needed */
  175. #ifdef THINK_P4
  176. extern short int **pnt;
  177. #else
  178. static short int **pnt;
  179. #endif
  180.  
  181. #define IFSET(X,Y) (pnt[X] == 0 ? 0 : (((pnt[X])[(Y)>>4] >> ((Y) & 0xf)) & 0x01))
  182.  
  183. #ifdef THINK_P4
  184. extern int plot3d_hidden();
  185. #else
  186. static int plot3d_hidden();
  187. #endif
  188.  
  189. #endif /* LITE */
  190.  
  191.  
  192.  
  193.  
  194.  
  195. #ifdef THINK_P4
  196. static draw_parametric_grid();
  197. static draw_non_param_grid();
  198. int draw_bottom_grid();
  199. static draw_3dxtics();
  200. static draw_3dytics();
  201. static draw_3dztics();
  202. static draw_series_3dxtics();
  203. static draw_series_3dytics();
  204. static draw_series_3dztics();
  205. static draw_set_3dxtics();
  206. static draw_set_3dytics();
  207. static draw_set_3dztics();
  208. static xtick();
  209. static ytick();
  210. static ztick();
  211. #else
  212. static plot3d_impulses();
  213. static plot3d_lines();
  214. static plot3d_points();
  215. static plot3d_dots();
  216. static cntr3d_impulses();
  217. static cntr3d_lines();
  218. static cntr3d_points();
  219. static cntr3d_dots();
  220. static update_extrema_pts();
  221. static setlinestyle();
  222. static draw_parametric_grid();
  223. static draw_non_param_grid();
  224. static draw_bottom_grid();
  225. static draw_3dxtics();
  226. static draw_3dytics();
  227. static draw_3dztics();
  228. static draw_series_3dxtics();
  229. static draw_series_3dytics();
  230. static draw_series_3dztics();
  231. static draw_set_3dxtics();
  232. static draw_set_3dytics();
  233. static draw_set_3dztics();
  234. static xtick();
  235. static ytick();
  236. static ztick();
  237. #endif
  238.  
  239. #ifdef __PUREC__
  240. /* a little problem with the 16bit int size of PureC. this completely broke
  241.    the hidded3d feature. doesn't really fix it, but I'm working at it.  (AL) */
  242. static int clip_point(int x, int y);
  243. static void clip_put_text(int x, int y, char *str);
  244. #endif
  245.  
  246. #ifndef max        /* Lattice C has max() in math.h, but shouldn't! */
  247. #define max(a,b) ((a > b) ? a : b)
  248. #endif
  249.  
  250. #ifndef min
  251. #define min(a,b) ((a < b) ? a : b)
  252. #endif
  253.  
  254. #define inrange(z,min,max) ((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)) )
  255.  
  256. #define apx_eq(x,y) (fabs(x-y) < 0.001)
  257. #ifndef abs
  258. #define abs(x) ((x) >= 0 ? (x) : -(x))
  259. #endif
  260. #define sqr(x) ((x) * (x))
  261.  
  262. /* Define the boundary of the plot
  263.  * These are computed at each call to do_plot, and are constant over
  264.  * the period of one do_plot. They actually only change when the term
  265.  * type changes and when the 'set size' factors change. 
  266.  */
  267. #ifdef THINK_P4
  268. extern int xleft, xright, ybot, ytop, xmiddle, ymiddle, xscaler, yscaler;
  269. #else
  270. static int xleft, xright, ybot, ytop, xmiddle, ymiddle, xscaler, yscaler;
  271. #endif
  272.  
  273. /* Boundary and scale factors, in user coordinates */
  274. /* x_min3d, x_max3d, y_min3d, y_max3d, z_min3d, z_max3d are local to this
  275.  * file and are not the same as variables of the same names in other files
  276.  */
  277. #ifdef THINK_P4
  278. extern double x_min3d, x_max3d, y_min3d, y_max3d, z_min3d, z_max3d;
  279. extern double xscale3d, yscale3d, zscale3d;
  280. extern double real_z_min3d, real_z_max3d;
  281. extern double min_sy_ox,min_sy_oy; /* obj. coords. for xy tics placement. */
  282. extern double min_sx_ox,min_sx_oy; /* obj. coords. for z tics placement. */
  283. #else
  284. static double x_min3d, x_max3d, y_min3d, y_max3d, z_min3d, z_max3d;
  285. static double xscale3d, yscale3d, zscale3d;
  286. static double real_z_min3d, real_z_max3d;
  287. static double min_sy_ox,min_sy_oy; /* obj. coords. for xy tics placement. */
  288. static double min_sx_ox,min_sx_oy; /* obj. coords. for z tics placement. */
  289. #endif
  290.  
  291. typedef double transform_matrix[4][4];
  292. #ifdef THINK_P4
  293. extern transform_matrix trans_mat;
  294. #else
  295. static transform_matrix trans_mat;
  296. #endif
  297.  
  298.  
  299. /* (DFK) Watch for cancellation error near zero on axes labels */
  300. #define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  301. #define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
  302. #define NearlyEqual(x,y,tic) (fabs((x)-(y)) < ((tic) * SIGNIF))
  303.  
  304. /* And the functions to map from user to terminal coordinates */
  305. #define map_x(x) (int)(x+0.5) /* maps floating point x to screen */ 
  306. #define map_y(y) (int)(y+0.5)    /* same for y */
  307.  
  308. /* And the functions to map from user 3D space into normalized -1..1 */
  309. #define map_x3d(x) ((x-x_min3d)*xscale3d-1.0)
  310. #define map_y3d(y) ((y-y_min3d)*yscale3d-1.0)
  311. #define map_z3d(z) ((z-z_min3d)*zscale3d-1.0)
  312.  
  313.  
  314. #ifdef THINK_P4
  315.  
  316. static mat_unit(mat)
  317. transform_matrix mat;
  318. {
  319.     int i, j;
  320.  
  321.     for (i = 0; i < 4; i++) for (j = 0; j < 4; j++)
  322.     if (i == j)
  323.         mat[i][j] = 1.0;
  324.     else
  325.         mat[i][j] = 0.0;
  326. }
  327.  
  328. static mat_trans(tx, ty, tz, mat)
  329. double tx, ty, tz;
  330. transform_matrix mat;
  331. {
  332.      mat_unit(mat);                                 /* Make it unit matrix. */
  333.      mat[3][0] = tx;
  334.      mat[3][1] = ty;
  335.      mat[3][2] = tz;
  336. }
  337.  
  338. #ifdef THINK_C
  339. mat_scale(sx, sy, sz, mat)
  340. #else
  341. static mat_scale(sx, sy, sz, mat)
  342. #endif
  343. double sx, sy, sz;
  344. transform_matrix mat;
  345. {
  346.      mat_unit(mat);                                 /* Make it unit matrix. */
  347.      mat[0][0] = sx;
  348.      mat[1][1] = sy;
  349.      mat[2][2] = sz;
  350. }
  351.  
  352. #ifdef THINK_C
  353. mat_rot_x(teta, mat)
  354. #else
  355. static mat_rot_x(teta, mat)
  356. #endif
  357. double teta;
  358. transform_matrix mat;
  359. {
  360.     double cos_teta, sin_teta;
  361.  
  362.     teta *= Pi / 180.0;
  363.     cos_teta = cos(teta);
  364.     sin_teta = sin(teta);
  365.  
  366.     mat_unit(mat);                                  /* Make it unit matrix. */
  367.     mat[1][1] = cos_teta;
  368.     mat[1][2] = -sin_teta;
  369.     mat[2][1] = sin_teta;
  370.     mat[2][2] = cos_teta;
  371. }
  372.  
  373. static mat_rot_y(teta, mat)
  374. double teta;
  375. transform_matrix mat;
  376. {
  377.     double cos_teta, sin_teta;
  378.  
  379.     teta *= Pi / 180.0;
  380.     cos_teta = cos(teta);
  381.     sin_teta = sin(teta);
  382.  
  383.     mat_unit(mat);                                  /* Make it unit matrix. */
  384.     mat[0][0] = cos_teta;
  385.     mat[0][2] = -sin_teta;
  386.     mat[2][0] = sin_teta;
  387.     mat[2][2] = cos_teta;
  388. }
  389.  
  390. #ifdef THINK_C
  391. mat_rot_z(teta, mat)
  392. #else
  393. static mat_rot_z(teta, mat)
  394. #endif
  395. double teta;
  396. transform_matrix mat;
  397. {
  398.     double cos_teta, sin_teta;
  399.  
  400.     teta *= Pi / 180.0;
  401.     cos_teta = cos(teta);
  402.     sin_teta = sin(teta);
  403.  
  404.     mat_unit(mat);                                  /* Make it unit matrix. */
  405.     mat[0][0] = cos_teta;
  406.     mat[0][1] = -sin_teta;
  407.     mat[1][0] = sin_teta;
  408.     mat[1][1] = cos_teta;
  409. }
  410.  
  411. /* Multiply two transform_matrix. Result can be one of two operands. */
  412. void mat_mult(mat_res, mat1, mat2)
  413. transform_matrix mat_res, mat1, mat2;
  414. {
  415.     int i, j, k;
  416.     transform_matrix mat_res_temp;
  417.  
  418.     for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) {
  419.         mat_res_temp[i][j] = 0;
  420.         for (k = 0; k < 4; k++) mat_res_temp[i][j] += mat1[i][k] * mat2[k][j];
  421.     }
  422.     for (i = 0; i < 4; i++) for (j = 0; j < 4; j++)
  423.     mat_res[i][j] = mat_res_temp[i][j];
  424. }
  425.  
  426. /* And the functions to map from user 3D space to terminal coordinates */
  427. #ifdef THINK_C
  428. int map3d_xy(x, y, z, xt, yt)
  429. #else
  430. static int map3d_xy(x, y, z, xt, yt)
  431. #endif
  432. double x, y, z;
  433. int *xt, *yt;
  434. {
  435.     int i,j;
  436.     double v[4], res[4],             /* Homogeneous coords. vectors. */
  437.     w = trans_mat[3][3];
  438.  
  439.     v[0] = map_x3d(x); /* Normalize object space to -1..1 */
  440.     v[1] = map_y3d(y);
  441.     v[2] = map_z3d(z);
  442.     v[3] = 1.0;
  443.  
  444.     for (i = 0; i < 2; i++) {                 /* Dont use the third axes (z). */
  445.         res[i] = trans_mat[3][i];     /* Initiate it with the weight factor. */
  446.         for (j = 0; j < 3; j++) res[i] += v[j] * trans_mat[j][i];
  447.     }
  448.  
  449.     for (i = 0; i < 3; i++) w += v[i] * trans_mat[i][3];
  450.     if (w == 0) w = 1e-5;
  451.  
  452.     *xt = ((int) (res[0] * xscaler / w)) + xmiddle;
  453.     *yt = ((int) (res[1] * yscaler / w)) + ymiddle;
  454. }
  455.  
  456. /* And the functions to map from user 3D space to terminal z coordinate */
  457. #ifdef THINK_C
  458. int map3d_z(x, y, z)
  459. #else
  460. static int map3d_z(x, y, z)
  461. #endif
  462. double x, y, z;
  463. {
  464.     int i, zt;
  465.     double v[4], res,                 /* Homogeneous coords. vectors. */
  466.     w = trans_mat[3][3];
  467.  
  468.     v[0] = map_x3d(x); /* Normalize object space to -1..1 */
  469.     v[1] = map_y3d(y);
  470.     v[2] = map_z3d(z);
  471.     v[3] = 1.0;
  472.  
  473.     res = trans_mat[3][2];               /* Initiate it with the weight factor. */
  474.     for (i = 0; i < 3; i++) res += v[i] * trans_mat[i][2];
  475.     if(w==0) w= 1e-5;
  476.     for (i = 0; i < 3; i++) w += v[i] * trans_mat[i][3];
  477.     zt = ((int) (res * 16384 / w));
  478.     return  zt;
  479. }
  480. #endif
  481.  
  482. #ifdef THINK_C_3
  483.  
  484. /* Initialize the line style using the current device and set hidden styles  */
  485. /* to it as well if hidden line removal is enabled.                 */
  486. static setlinestyle(style)
  487. int style;
  488. {
  489.     register struct termentry *t = &term_tbl[term];
  490.  
  491.     (*t->linetype)(style);
  492.  
  493. #ifndef LITE
  494.     if (hidden3d) {
  495.     hidden_line_type_above = style;
  496.     hidden_line_type_below = style;
  497.     }
  498. #endif  /* LITE */
  499. }
  500.  
  501. #ifndef LITE
  502. /* Initialize the necessary steps for hidden line removal. */
  503. static void init_hidden_line_removal()
  504. {
  505.   int i;
  506.   /*  We want to keep the bitmap size less than 2048x2048, so we choose
  507.    *  integer dividers for the x and y coordinates to keep the x and y
  508.    *  ranges less than 2048.  In practice, the x and y sizes for the bitmap
  509.    *  will be somewhere between 1024 and 2048, except in cases where the
  510.    *  coordinates ranges for the device are already less than 1024.
  511.    *  We do this mainly to control the size of the bitmap, but it also
  512.    *  speeds up the computation.  We maintain separate dividers for
  513.    *  x and y.
  514.    */
  515.   xfact = (xright-xleft)/1024;
  516.   yfact = (ytop-ybot)/1024;
  517.   if(xfact == 0) xfact=1;
  518.   if(yfact == 0) yfact=1;
  519.   if(pnt == 0){
  520.     i = sizeof(short int*)*(XREDUCE(xright) - XREDUCE(xleft) + 1);
  521.     pnt = (short int **) alloc((unsigned long)i, "hidden");
  522.     bzero(pnt,i);
  523.   };
  524.   ymin_hl = (short int *) alloc((unsigned long)sizeof(short int)*
  525.                 (XREDUCE(xright) - XREDUCE(xleft) + 1), "hidden");
  526.   ymax_hl = (short int *) alloc((unsigned long)sizeof(short int)*
  527.                 (XREDUCE(xright) - XREDUCE(xleft) + 1), "hidden");
  528. }
  529.  
  530. /* Reset the hidden line data to a fresh start.                     */
  531. static void reset_hidden_line_removal()
  532. {
  533.     int i;
  534.     if(pnt){
  535.       for(i=0;i<=XREDUCE(xright)-XREDUCE(xleft);i++) {
  536.     if(pnt[i])
  537.       { free(pnt[i]); pnt[i] = 0;};
  538.       };
  539.     };
  540. }
  541.  
  542. /* Terminates the hidden line removal process. Free any memory allocated by  */
  543. /* init_hidden_line_removal above.                         */
  544. static void term_hidden_line_removal()
  545. {
  546.      if(pnt){
  547.        int j;
  548.        for(j=0;j<=XREDUCE(xright)-XREDUCE(xleft);j++) {
  549.      if(pnt[j])
  550.        { free(pnt[j]); pnt[j] = 0;};
  551.        };
  552.        free(pnt);
  553.        pnt = 0;
  554.      };
  555.    free(ymin_hl);
  556.    free(ymax_hl);
  557. }
  558. #endif /* not LITE */
  559.  
  560. /* Test a single point to be within the xleft,xright,ybot,ytop bbox.
  561.  * Sets the returned integers 4 l.s.b. as follows:
  562.  * bit 0 if to the left of xleft.
  563.  * bit 1 if to the right of xright.
  564.  * bit 2 if above of ytop.
  565.  * bit 3 if below of ybot.
  566.  * 0 is returned if inside.
  567.  */
  568. static int clip_point(x, y)
  569. int x, y;
  570. {
  571.     int ret_val = 0;
  572.  
  573.     if (x < xleft) ret_val |= 0x01;
  574.     if (x > xright) ret_val |= 0x02;
  575.     if (y < ybot) ret_val |= 0x04;
  576.     if (y > ytop) ret_val |= 0x08;
  577.  
  578.     return ret_val;
  579. }
  580.  
  581.  
  582. /* Clip the given line to drawing coords defined as xleft,xright,ybot,ytop.
  583.  *   This routine uses the cohen & sutherland bit mapping for fast clipping -
  584.  * see "Principles of Interactive Computer Graphics" Newman & Sproull page 65.
  585.  */
  586. static void draw_clip_line(x1, y1, x2, y2)
  587. int x1, y1, x2, y2;
  588. {
  589.     int x, y, dx, dy, x_intr[2], y_intr[2], count, pos1, pos2;
  590.     register struct termentry *t = &term_tbl[term];
  591.  
  592.     pos1 = clip_point(x1, y1);
  593.     pos2 = clip_point(x2, y2);
  594.     if (pos1 || pos2) {
  595.     if (pos1 & pos2) return;          /* segment is totally out. */
  596.  
  597.     /* Here part of the segment MAY be inside. test the intersection
  598.      * of this segment with the 4 boundaries for hopefully 2 intersections
  599.      * in. If non found segment is totaly out.
  600.      */
  601.     count = 0;
  602.     dx = x2 - x1;
  603.     dy = y2 - y1;
  604.  
  605.     /* Find intersections with the x parallel bbox lines: */
  606.     if (dy != 0) {
  607.         x = (ybot - y2) * dx / dy + x2;        /* Test for ybot boundary. */
  608.         if (x >= xleft && x <= xright) {
  609.         x_intr[count] = x;
  610.         y_intr[count++] = ybot;
  611.         }
  612.         x = (ytop - y2) * dx / dy + x2;        /* Test for ytop boundary. */
  613.         if (x >= xleft && x <= xright) {
  614.         x_intr[count] = x;
  615.         y_intr[count++] = ytop;
  616.         }
  617.     }
  618.  
  619.     /* Find intersections with the y parallel bbox lines: */
  620.     if (dx != 0) {
  621.         y = (xleft - x2) * dy / dx + y2;      /* Test for xleft boundary. */
  622.         if (y >= ybot && y <= ytop) {
  623.         x_intr[count] = xleft;
  624.         y_intr[count++] = y;
  625.         }
  626.         y = (xright - x2) * dy / dx + y2;    /* Test for xright boundary. */
  627.         if (y >= ybot && y <= ytop) {
  628.         x_intr[count] = xright;
  629.         y_intr[count++] = y;
  630.         }
  631.     }
  632.  
  633.     if (count == 2) {
  634.         int x_max, x_min, y_max, y_min;
  635.  
  636.         x_min = min(x1, x2);
  637.         x_max = max(x1, x2);
  638.         y_min = min(y1, y2);
  639.         y_max = max(y1, y2);
  640.  
  641.         if (pos1 && pos2) {               /* Both were out - update both */
  642.         x1 = x_intr[0];
  643.         y1 = y_intr[0];
  644.         x2 = x_intr[1];
  645.         y2 = y_intr[1];
  646.         }
  647.         else if (pos1) {           /* Only x1/y1 was out - update only it */
  648.         if (dx * (x2 - x_intr[0]) + dy * (y2 - y_intr[0]) > 0) {
  649.             x1 = x_intr[0];
  650.             y1 = y_intr[0];
  651.         }
  652.         else {
  653.             x1 = x_intr[1];
  654.             y1 = y_intr[1];
  655.         }
  656.         }
  657.         else {                      /* Only x2/y2 was out - update only it */
  658.         if (dx * (x_intr[0] - x1) + dy * (y_intr[0] - x1) > 0) {
  659.             x2 = x_intr[0];
  660.             y2 = y_intr[0];
  661.         }
  662.         else {
  663.             x2 = x_intr[1];
  664.             y2 = y_intr[1];
  665.         }
  666.         }
  667.  
  668.         if (x1 < x_min || x1 > x_max ||
  669.         x2 < x_min || x2 > x_max ||
  670.         y1 < y_min || y1 > y_max ||
  671.         y2 < y_min || y2 > y_max) return;
  672.     }
  673.     else
  674.         return;
  675.     }
  676.  
  677. #ifndef LITE
  678.     if(hidden3d && draw_surface)
  679.       {
  680.     char flag;
  681.     register int xv, yv, errx, erry, err;
  682.     register int xvr, yvr;
  683.     int xve, yve;
  684.     register int dy, nstep, dyr;
  685.     int i;
  686.     if (x1 > x2){
  687.       xvr = x2;
  688.       yvr = y2;
  689.       xve = x1;
  690.       yve = y1;
  691.     } else {
  692.       xvr = x1;
  693.       yvr = y1;
  694.       xve = x2;
  695.       yve = y2;
  696.     };
  697.     errx = XREDUCE(xve) - XREDUCE(xvr);
  698.     erry = YREDUCE(yve) - YREDUCE(yvr);
  699.     dy = (erry > 0 ? 1 : -1);
  700.     dyr = dy*yfact;
  701.     switch (dy){
  702.     case 1:
  703.       nstep = errx + erry;
  704.       errx = -errx;
  705.       break;
  706.     case -1:
  707.       nstep = errx - erry;
  708.       errx = -errx;
  709.       erry = -erry;
  710.       break;
  711.     };
  712.     err = errx + erry;
  713.     errx <<= 1;
  714.     erry <<= 1;
  715.     xv = XREDUCE(xvr) - XREDUCE(xleft);
  716.     yv = YREDUCE(yvr) - YREDUCE(ybot);
  717.     (*t->move)(xvr,yvr);
  718.     if( !IFSET(xv,yv) ) flag = 0;
  719.     else flag = 1;
  720.     if(!hidden_no_update){ /* Check first point */
  721.       if (xv < xmin_hl) xmin_hl = xv;
  722.       if (xv > xmax_hl) xmax_hl = xv;
  723.       if (yv > ymax_hl[xv]) ymax_hl[xv] = yv;
  724.       if (yv < ymin_hl[xv]) ymin_hl[xv] = yv;
  725.     };
  726.     for (i=0;i<nstep;i++){
  727.       if (err < 0){
  728.         xv ++;
  729.         xvr += xfact;
  730.         err += erry;
  731.       } else {
  732.         yv += dy;
  733.         yvr += dyr;
  734.         err += errx;
  735.       };
  736.       if( !IFSET(xv,yv)){
  737.         if(flag != 0) {(*t->move)(xvr,yvr); flag = 0;};
  738.       } else {
  739.         if(flag == 0) {(*t->vector)(xvr,yvr); flag = 1;};
  740.       };
  741.       if(!hidden_no_update){
  742.         if (xv < xmin_hl) xmin_hl = xv;
  743.         if (xv > xmax_hl) xmax_hl = xv;
  744.         if (yv > ymax_hl[xv]) ymax_hl[xv] = yv;
  745.         if (yv < ymin_hl[xv]) ymin_hl[xv] = yv;
  746.       };
  747.     };
  748.     if (flag == 0) (*t->vector)(xve, yve);
  749.     return;
  750.       };
  751. #endif /* not LITE */
  752.     if(!suppressMove) (*t->move)(x1,y1);
  753.     (*t->vector)(x2,y2);
  754. }
  755.  
  756. /* Two routine to emulate move/vector sequence using line drawing routine. */
  757. static int move_pos_x, move_pos_y;
  758.  
  759. static void clip_move(x,y)
  760. int x,y;
  761. {
  762.     move_pos_x = x;
  763.     move_pos_y = y;
  764. }
  765.  
  766. static void clip_vector(x,y)
  767. int x,y;
  768. {
  769.     draw_clip_line(move_pos_x,move_pos_y, x, y);
  770.     move_pos_x = x;
  771.     move_pos_y = y;
  772. }
  773.  
  774. /* And text clipping routine. */
  775. static void clip_put_text(x, y, str)
  776. int x,y;
  777. char *str;
  778. {
  779.     register struct termentry *t = &term_tbl[term];
  780.  
  781.     if (clip_point(x, y)) return;
  782.  
  783.     (*t->put_text)(x,y,str);
  784. }
  785.  
  786. /* (DFK) For some reason, the Sun386i compiler screws up with the CheckLog 
  787.  * macro, so I write it as a function on that machine.
  788.  */
  789. #ifndef sun386
  790. /* (DFK) Use 10^x if logscale is in effect, else x */
  791. #define CheckLog(is_log, base_log, x) ((is_log) ? pow(base_log, (x)) : (x))
  792. #else
  793. static double
  794. CheckLog(is_log, base_log, x)
  795.      TBOOLEAN is_log;
  796.      double base_log;
  797.      double x;
  798. {
  799.   if (is_log)
  800.     return(pow(base_log, x));
  801.   else
  802.     return(x);
  803. }
  804. #endif /* sun386 */
  805.  
  806. static double
  807. LogScale(coord, is_log, log_base_log, what, axis)
  808.     double coord;            /* the value */
  809.     TBOOLEAN is_log;            /* is this axis in logscale? */
  810.     double log_base_log;        /* if so, the log of its base */
  811.     char *what;            /* what is the coord for? */
  812.     char *axis;            /* which axis is this for ("x" or "y")? */
  813. {
  814.     if (is_log) {
  815.        if (coord <= 0.0) {
  816.           char errbuf[100];        /* place to write error message */
  817.         (void) sprintf(errbuf,"%s has %s coord of %g; must be above 0 for log scale!",
  818.                 what, axis, coord);
  819.           (*term_tbl[term].text)();
  820.           (void) fflush(outfile);
  821.           int_error(errbuf, NO_CARET);
  822.        } else
  823.         return(log(coord)/log_base_log);
  824.     }
  825.     return(coord);
  826. }
  827.  
  828. /* borders of plotting area */
  829. /* computed once on every call to do_plot */
  830. static boundary3d(scaling)
  831.     TBOOLEAN scaling;        /* TRUE if terminal is doing the scaling */
  832. {
  833.     register struct termentry *t = &term_tbl[term];
  834.     /* luecken@udel.edu modifications
  835.        sizes the plot to take up more of available resolution */
  836.     xleft = (t->h_char)*2 + (t->h_tic);
  837.     xright = (scaling ? 1 : xsize) * (t->xmax) - (t->h_char)*2 - (t->h_tic);
  838.     ybot = (t->v_char)*5/2 + 1;
  839.     ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char)*5/2 - 1;
  840.     xmiddle = (xright + xleft) / 2;
  841.     ymiddle = (ytop + ybot) / 2;
  842.     xscaler = (xright - xleft) * 4 / 7;
  843.     yscaler = (ytop - ybot) * 4 / 7;
  844. }
  845.  
  846. static double dbl_raise(x,y)
  847. double x;
  848. int y;
  849. {
  850. register int i;
  851. double val;
  852.  
  853.     val = 1.0;
  854.     for (i=0; i < abs(y); i++)
  855.         val *= x;
  856.     if (y < 0 ) return (1.0/val);
  857.     return(val);
  858. }
  859.  
  860.  
  861. static double make_3dtics(tmin,tmax,axis,logscale, base_log)
  862. double tmin,tmax;
  863. int axis;
  864. TBOOLEAN logscale;
  865. double base_log;
  866. {
  867. int x1,y1,x2,y2;
  868. register double xr,xnorm,tics,tic,l10;
  869.  
  870.     xr = fabs(tmin-tmax);
  871.  
  872.     /* Compute length of axis in screen space coords. */
  873.     switch (axis) {
  874.         case 'x':
  875.             map3d_xy(tmin,0.0,0.0,&x1,&y1);
  876.             map3d_xy(tmax,0.0,0.0,&x2,&y2);
  877.             break;
  878.         case 'y':
  879.             map3d_xy(0.0,tmin,0.0,&x1,&y1);
  880.             map3d_xy(0.0,tmax,0.0,&x2,&y2);
  881.             break;
  882.         case 'z':
  883.             map3d_xy(0.0,0.0,tmin,&x1,&y1);
  884.             map3d_xy(0.0,0.0,tmax,&x2,&y2);
  885.             break;
  886.     }
  887.  
  888.     if (((long) (x1-x2))*(x1-x2) + ((long) (y1-y2))*(y1-y2) <
  889.         sqr(3L * term_tbl[term].h_char))
  890.         return -1.0;                              /* No tics! */
  891.  
  892.     l10 = log10(xr);
  893.     if (logscale) {
  894.         tic = dbl_raise(base_log,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  895.         if (tic < 1.0)
  896.             tic = 1.0;
  897.     } else {
  898.         xnorm = pow(10.0,l10-(double)((l10 >= 0.0 ) ? (int)l10 : ((int)l10-1)));
  899.         if (xnorm <= 5)
  900.             tics = 0.5;
  901.         else tics = 1.0;
  902.         tic = tics * dbl_raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  903.     }
  904.     return(tic);
  905. }
  906.  
  907. do_3dplot(plots, pcount, min_x, max_x, min_y, max_y, min_z, max_z)
  908. struct surface_points *plots;
  909. int pcount;            /* count of plots in linked list */
  910. double min_x, max_x;
  911. double min_y, max_y;
  912. double min_z, max_z;
  913. {
  914. register struct termentry *t = &term_tbl[term];
  915. register int surface;
  916. register struct surface_points *this_plot;
  917. int xl, yl, linetypeOffset = 0;
  918.             /* only a Pyramid would have this many registers! */
  919. double xtemp, ytemp, ztemp, temp;
  920. struct text_label *this_label;
  921. struct arrow_def *this_arrow;
  922. TBOOLEAN scaling;
  923. transform_matrix mat;
  924.  
  925. /* Initiate transformation matrix using the global view variables. */
  926.     mat_rot_z(surface_rot_z, trans_mat);
  927.     mat_rot_x(surface_rot_x, mat);
  928.     mat_mult(trans_mat, trans_mat, mat);
  929.     mat_scale(surface_scale / 2.0, surface_scale / 2.0, surface_scale / 2.0, mat);
  930.     mat_mult(trans_mat, trans_mat, mat);
  931.  
  932. /* modify min_z/max_z so it will zscale properly. */
  933.     ztemp = (max_z - min_z) / (2.0 * surface_zscale);
  934.     temp = (max_z + min_z) / 2.0;
  935.     min_z = temp - ztemp;
  936.     max_z = temp + ztemp;
  937.  
  938. /* store these in variables global to this file */
  939. /* otherwise, we have to pass them around a lot */
  940.     x_min3d = min_x;
  941.     x_max3d = max_x;
  942.     y_min3d = min_y;
  943.     y_max3d = max_y;
  944.     z_min3d = min_z;
  945.     z_max3d = max_z;
  946.  
  947.     /* The extrema need to be set even when a surface is not being
  948.      * drawn.   Without this, gnuplot used to assume that the X and
  949.      * Y axis started at zero.   -RKC
  950.      */
  951.  
  952.     /* find (bottom) left corner of grid */
  953.     min_sx_ox = min_x;
  954.     min_sx_oy = min_y;
  955.     /* find bottom (right) corner of grid */
  956.     min_sy_ox = max_x;
  957.     min_sy_oy = min_y;
  958.  
  959.  
  960.     if (polar)
  961.     int_error("Cannot splot in polar coordinate system.", NO_CARET);
  962.  
  963.     if (z_min3d == VERYLARGE || z_max3d == -VERYLARGE ||
  964.     x_min3d == VERYLARGE || x_max3d == -VERYLARGE ||
  965.     y_min3d == VERYLARGE || y_max3d == -VERYLARGE)
  966.         int_error("all points undefined!", NO_CARET);
  967.  
  968.     /* If we are to draw the bottom grid make sure zmin is updated properly. */
  969.     if (xtics || ytics || grid)
  970.     z_min3d -= (max_z - min_z) * ticslevel;
  971.  
  972. /*  This used be x_max3d == x_min3d, but that caused an infinite loop once. */
  973.     if (fabs(x_max3d - x_min3d) < zero)
  974.     int_error("x_min3d should not equal x_max3d!",NO_CARET);
  975.     if (fabs(y_max3d - y_min3d) < zero)
  976.     int_error("y_min3d should not equal y_max3d!",NO_CARET);
  977.     if (fabs(z_max3d - z_min3d) < zero)
  978.     int_error("z_min3d should not equal z_max3d!",NO_CARET);
  979.  
  980. #ifndef LITE
  981.     if (hidden3d) {
  982.     struct surface_points *plot;
  983.   
  984.         /* Verify data is hidden line removable - grid based. */
  985.           for (plot = plots; plot != NULL; plot = plot->next_sp) {
  986.          if (plot->plot_type == DATA3D && !plot->has_grid_topology){
  987.           fprintf(stderr,"Notice: Cannot remove hidden lines from non grid data\n");
  988.               return(0);
  989.             }
  990.     
  991.         }
  992.     }
  993. #endif /* not LITE */
  994.  
  995. /* INITIALIZE TERMINAL */
  996.     if (!term_init) {
  997.     (*t->init)();
  998.     term_init = TRUE;
  999.     }
  1000.     screen_ok = FALSE;
  1001.     scaling = (*t->scale)(xsize, ysize);
  1002.     (*t->graphics)();
  1003.  
  1004.     /* now compute boundary for plot (xleft, xright, ytop, ybot) */
  1005.     boundary3d(scaling);
  1006.  
  1007. /* SCALE FACTORS */
  1008.     zscale3d = 2.0/(z_max3d - z_min3d);
  1009.     yscale3d = 2.0/(y_max3d - y_min3d);
  1010.     xscale3d = 2.0/(x_max3d - x_min3d);
  1011.  
  1012.     (*t->linetype)(-2); /* border linetype */
  1013.  
  1014. /* PLACE TITLE */
  1015.     if (*title != 0) {
  1016.         int x, y;
  1017.  
  1018.         x = title_xoffset * t->h_char;
  1019.         y = title_yoffset * t->v_char;
  1020.  
  1021.         if ((*t->justify_text)(CENTRE)) 
  1022.             (*t->put_text)(x+(xleft+xright)/2, 
  1023.                        y+ytop+(t->v_char), title);
  1024.         else
  1025.             (*t->put_text)(x+(xleft+xright)/2 - strlen(title)*(t->h_char)/2,
  1026.                        y+ytop+(t->v_char), title);
  1027.     }
  1028.  
  1029. /* PLACE TIMEDATE */
  1030.     if (timedate) {
  1031.         int x, y;
  1032.  
  1033.         x = time_xoffset * t->h_char;
  1034.         y = time_yoffset * t->v_char;
  1035.         dated = time( (time_t *) 0);
  1036.         tdate = ctime( &dated);
  1037.         tdate[24]='\0';
  1038.         if ((*t->text_angle)(1)) {
  1039.             if ((*t->justify_text)(CENTRE)) {
  1040.                 (*t->put_text)(x+(t->v_char),
  1041.                          y+ybot+4*(t->v_char), tdate);
  1042.             }
  1043.             else {
  1044.                 (*t->put_text)(x+(t->v_char),
  1045.                          y+ybot+4*(t->v_char)-(t->h_char)*strlen(ylabel)/2, 
  1046.                          tdate);
  1047.             }
  1048.         }
  1049.         else {
  1050.             (void)(*t->justify_text)(LEFT);
  1051.             (*t->put_text)(x,
  1052.                          y+ybot-1*(t->v_char), tdate);
  1053.         }
  1054.         (void)(*t->text_angle)(0);
  1055.     }
  1056.  
  1057. /* PLACE LABELS */
  1058.     for (this_label = first_label; this_label!=NULL;
  1059.             this_label=this_label->next ) {
  1060.         int x,y;
  1061.  
  1062.         xtemp = LogScale(this_label->x, is_log_x, log_base_log_x, "label", "x");
  1063.         ytemp = LogScale(this_label->y, is_log_y, log_base_log_y, "label", "y");
  1064.         ztemp = LogScale(this_label->z, is_log_z, log_base_log_z, "label", "z");
  1065.             map3d_xy(xtemp,ytemp,ztemp, &x, &y);
  1066.  
  1067.         if ((*t->justify_text)(this_label->pos)) {
  1068.             (*t->put_text)(x,y,this_label->text);
  1069.         }
  1070.         else {
  1071.             switch(this_label->pos) {
  1072.                 case  LEFT:
  1073.                     (*t->put_text)(x,y,this_label->text);
  1074.                     break;
  1075.                 case CENTRE:
  1076.                     (*t->put_text)(x -
  1077.                         (t->h_char)*strlen(this_label->text)/2,
  1078.                         y, this_label->text);
  1079.                     break;
  1080.                 case RIGHT:
  1081.                     (*t->put_text)(x -
  1082.                         (t->h_char)*strlen(this_label->text),
  1083.                         y, this_label->text);
  1084.                     break;
  1085.             }
  1086.          }
  1087.      }
  1088.  
  1089. /* PLACE ARROWS */
  1090.     (*t->linetype)(0);    /* arrow line type */
  1091.     for (this_arrow = first_arrow; this_arrow!=NULL;
  1092.         this_arrow = this_arrow->next ) {
  1093.     int sx,sy,ex,ey;
  1094.  
  1095.     xtemp = LogScale(this_arrow->sx, is_log_x, log_base_log_x, "arrow", "x");
  1096.     ytemp = LogScale(this_arrow->sy, is_log_y, log_base_log_y, "arrow", "y");
  1097.     ztemp = LogScale(this_arrow->sz, is_log_z, log_base_log_z, "arrow", "z");
  1098.     map3d_xy(xtemp,ytemp,ztemp, &sx, &sy);
  1099.  
  1100.     xtemp = LogScale(this_arrow->ex, is_log_x, log_base_log_x, "arrow", "x");
  1101.     ytemp = LogScale(this_arrow->ey, is_log_y, log_base_log_y, "arrow", "y");
  1102.     ztemp = LogScale(this_arrow->ez, is_log_z, log_base_log_z, "arrow", "z");
  1103.     map3d_xy(xtemp,ytemp,ztemp, &ex, &ey);
  1104.  
  1105.     (*t->arrow)(sx, sy, ex, ey, this_arrow->head);
  1106.     }
  1107.  
  1108. #ifndef LITE
  1109.     if (hidden3d && draw_surface) {
  1110.     init_hidden_line_removal();
  1111.     reset_hidden_line_removal();
  1112.     hidden_active = TRUE;
  1113.     }
  1114. #endif /* not LITE */
  1115.  
  1116. /* DRAW SURFACES AND CONTOURS */
  1117.     real_z_min3d = min_z;
  1118.     real_z_max3d = max_z;
  1119.     if (key == -1) {
  1120.         xl = xright  - (t->h_tic) - (t->h_char)*5;
  1121.         yl = ytop - (t->v_tic) - (t->v_char);
  1122.     }
  1123.     if (key == 1) {
  1124.         xtemp = LogScale(key_x, is_log_x, log_base_log_x, "key", "x");
  1125.         ytemp = LogScale(key_y, is_log_y, log_base_log_y, "key", "y");
  1126.         ztemp = LogScale(key_z, is_log_z, log_base_log_z, "key", "z");
  1127.         map3d_xy(xtemp,ytemp,ztemp, &xl, &yl);
  1128.     }
  1129.  
  1130. #ifndef LITE
  1131.     if (hidden3d && draw_surface) plot3d_hidden(plots,pcount);
  1132. #endif /* not LITE */
  1133.     this_plot = plots;
  1134.     for (surface = 0;
  1135.          surface < pcount;
  1136.          this_plot = this_plot->next_sp, surface++) {
  1137. #ifndef LITE
  1138.         if ( hidden3d )
  1139.             hidden_no_update = FALSE;
  1140. #endif /* not LITE */
  1141.  
  1142.         if (draw_surface) {
  1143.             (*t->linetype)(this_plot->line_type);
  1144. #ifndef LITE
  1145.             if (hidden3d) {
  1146.             hidden_line_type_above = this_plot->line_type;
  1147.             hidden_line_type_below = this_plot->line_type + 1;
  1148.             }
  1149. #endif /* not LITE */            
  1150.             if (key != 0 && this_plot->title) {
  1151.             if ((*t->justify_text)(RIGHT)) {
  1152.                 clip_put_text(xl,
  1153.                       yl,this_plot->title);
  1154.             }
  1155.             else {
  1156.                 if (inrange(xl-(t->h_char)*strlen(this_plot->title), 
  1157.                     xleft, xright))
  1158.                 clip_put_text(xl-(t->h_char)*strlen(this_plot->title),
  1159.                           yl,this_plot->title);
  1160.             }
  1161.             }
  1162.             
  1163.             switch(this_plot->plot_style) {
  1164.                 case BOXES: /* can't do boxes in 3d yet so use impulses */
  1165.                 case IMPULSES: {
  1166.                 if (key != 0 && this_plot->title) {
  1167.                 clip_move(xl+(t->h_char),yl);
  1168.                 clip_vector(xl+4*(t->h_char),yl);
  1169.                 }
  1170.                 if (!(hidden3d && draw_surface))
  1171.                   plot3d_impulses(this_plot);
  1172.                 break;
  1173.             }
  1174.             case LINES: {
  1175.                 if (key != 0 && this_plot->title) {
  1176.                 clip_move(xl+(int)(t->h_char),yl);
  1177.                 clip_vector(xl+(int)(4*(t->h_char)),yl);
  1178.                 }
  1179.                 if (!(hidden3d && draw_surface))
  1180.                   plot3d_lines(this_plot);
  1181.                 break;
  1182.             }
  1183.             case ERRORBARS:    /* ignored; treat like points */
  1184.             case POINTSTYLE: {
  1185.                 if (key != 0 && this_plot->title 
  1186.                 && !clip_point(xl+2*(t->h_char),yl)) {
  1187.                 (*t->point)(xl+2*(t->h_char),yl,
  1188.                         this_plot->point_type);
  1189.                 }
  1190.                 if (!(hidden3d && draw_surface))
  1191.                   plot3d_points(this_plot);
  1192.                 break;
  1193.             }
  1194.             case LINESPOINTS: {
  1195.                 /* put lines */
  1196.                 if (key != 0 && this_plot->title) {
  1197.                 clip_move(xl+(t->h_char),yl);
  1198.                 clip_vector(xl+4*(t->h_char),yl);
  1199.                 }
  1200.                  if (!(hidden3d && draw_surface))
  1201.                    plot3d_lines(this_plot);
  1202.             
  1203.                 /* put points */
  1204.                 if (key != 0 && this_plot->title 
  1205.                 && !clip_point(xl+2*(t->h_char),yl)) {
  1206.                 (*t->point)(xl+2*(t->h_char),yl,
  1207.                         this_plot->point_type);
  1208.                 }
  1209.                 if (!(hidden3d && draw_surface))
  1210.                   plot3d_points(this_plot);
  1211.                 break;
  1212.             }
  1213.             case DOTS: {
  1214.                 if (key != 0 && this_plot->title
  1215.                 && !clip_point(xl+2*(t->h_char),yl)) {
  1216.                 (*t->point)(xl+2*(t->h_char),yl, -1);
  1217.                 }
  1218.                 if (!(hidden3d && draw_surface))
  1219.                   plot3d_dots(this_plot);
  1220.                 break;
  1221.             }
  1222.             }
  1223.             if (key != 0 && this_plot->title)
  1224.                 yl = yl - (t->v_char);
  1225.         }
  1226.  
  1227. #ifndef LITE
  1228.         if ( hidden3d ) {
  1229.             hidden_no_update = TRUE;
  1230.             hidden_line_type_above = this_plot->line_type + (hidden3d ? 2 : 1);
  1231.             hidden_line_type_below = this_plot->line_type + (hidden3d ? 2 : 1);
  1232.         }
  1233. #endif /* not LITE */
  1234.  
  1235.         if (draw_contour && this_plot->contours != NULL) {
  1236.             struct gnuplot_contours *cntrs = this_plot->contours;
  1237.  
  1238.             (*t->linetype)(this_plot->line_type + (hidden3d ? 2 : 1));
  1239.  
  1240.             if (key != 0 && this_plot->title 
  1241.                       && !(draw_surface && label_contours) ) {
  1242.                 if ((*t->justify_text)(RIGHT)) {
  1243.                     clip_put_text(xl,
  1244.                         yl,this_plot->title);
  1245.                 }
  1246.                 else {
  1247.                     if (inrange(xl-(t->h_char)*strlen(this_plot->title), 
  1248.                              xleft, xright))
  1249.                      clip_put_text(xl-(t->h_char)*strlen(this_plot->title),
  1250.                                  yl,this_plot->title);
  1251.                 }
  1252.                 switch(this_plot->plot_style) {
  1253.                     case IMPULSES:
  1254.                         clip_move(xl+(t->h_char),yl);
  1255.                         clip_vector(xl+4*(t->h_char),yl);
  1256.                         break;
  1257.                     case LINES:
  1258.                         clip_move(xl+(int)(t->h_char),yl);
  1259.                         clip_vector(xl+(int)(4*(t->h_char)),yl);
  1260.                         break;
  1261.                     case ERRORBARS: /* ignored; treat like points */
  1262.                     case POINTSTYLE:
  1263.                         if (!clip_point(xl+2*(t->h_char),yl)) {
  1264.                              (*t->point)(xl+2*(t->h_char),yl,
  1265.                                     this_plot->point_type);
  1266.                         }
  1267.                         break;
  1268.                     case LINESPOINTS:
  1269.                         clip_move(xl+(int)(t->h_char),yl);
  1270.                         clip_vector(xl+(int)(4*(t->h_char)),yl);
  1271.                         break;
  1272.                     case DOTS:
  1273.                         if (!clip_point(xl+2*(t->h_char),yl)) {
  1274.                              (*t->point)(xl+2*(t->h_char),yl, -1);
  1275.                         }
  1276.                         break;
  1277.                 }
  1278.                 yl = yl - (t->v_char);
  1279.             }
  1280.             yl = yl + (t->v_char);
  1281.  
  1282.              linetypeOffset = this_plot->line_type + (hidden3d ? 2 : 1);
  1283.             while (cntrs) {
  1284.                  if(label_contours && cntrs->isNewLevel) {
  1285.                      (*t->linetype)(linetypeOffset++);
  1286. #ifndef LITE
  1287.                      if(hidden3d) hidden_line_type_below = hidden_line_type_above = linetypeOffset-1;
  1288. #endif /* not LITE */
  1289.                      yl -= (t->v_char);
  1290.                      if ((*t->justify_text)(RIGHT)) {
  1291.                         clip_put_text(xl,
  1292.                             yl,cntrs->label);
  1293.                     }
  1294.                     else {
  1295.                         if (inrange(xl-(t->h_char)*strlen(cntrs->label),
  1296.                                  xleft, xright))
  1297.                          clip_put_text(xl-(t->h_char)*strlen(cntrs->label),
  1298.                                      yl,cntrs->label);
  1299.                     }
  1300.                     switch(this_plot->plot_style) {
  1301.                         case IMPULSES:
  1302.                             clip_move(xl+(t->h_char),yl);
  1303.                             clip_vector(xl+4*(t->h_char),yl);
  1304.                             break;
  1305.                         case LINES:
  1306.                             clip_move(xl+(int)(t->h_char),yl);
  1307.                             clip_vector(xl+(int)(4*(t->h_char)),yl);
  1308.                             break;
  1309.                         case ERRORBARS: /* ignored; treat like points */
  1310.                         case POINTSTYLE:
  1311.                             if (!clip_point(xl+2*(t->h_char),yl)) {
  1312.                                  (*t->point)(xl+2*(t->h_char),yl,
  1313.                                         this_plot->point_type);
  1314.                             }
  1315.                             break;
  1316.                         case LINESPOINTS:
  1317.                             clip_move(xl+(int)(t->h_char),yl);
  1318.                             clip_vector(xl+(int)(4*(t->h_char)),yl);
  1319.                             break;
  1320.                         case DOTS:
  1321.                             if (!clip_point(xl+2*(t->h_char),yl)) {
  1322.                                  (*t->point)(xl+2*(t->h_char),yl, -1);
  1323.                             }
  1324.                             break;
  1325.                     }
  1326.                  }
  1327.                 switch(this_plot->plot_style) {
  1328.                     case IMPULSES:
  1329.                            cntr3d_impulses(cntrs, this_plot);
  1330.                         break;
  1331.                     case LINES:
  1332.                         cntr3d_lines(cntrs);
  1333.                         break;
  1334.                     case ERRORBARS: /* ignored; treat like points */
  1335.                     case POINTSTYLE:
  1336.                         cntr3d_points(cntrs, this_plot);
  1337.                         break;
  1338.                     case LINESPOINTS:
  1339.                         cntr3d_lines(cntrs);
  1340.                         cntr3d_points(cntrs, this_plot);
  1341.                         break;
  1342.                     case DOTS:
  1343.                         cntr3d_dots(cntrs);
  1344.                         break;
  1345.                 }
  1346.                 cntrs = cntrs->next;
  1347.             }
  1348.             if (key != 0 && this_plot->title)
  1349.               yl = yl - (t->v_char);
  1350.         }
  1351.  
  1352.         if (surface == 0)
  1353.             draw_bottom_grid(this_plot,real_z_min3d,real_z_max3d);
  1354.     }
  1355.     (*t->text)();
  1356.     (void) fflush(outfile);
  1357.  
  1358. #ifndef LITE
  1359.     if (hidden3d) {
  1360.         term_hidden_line_removal();
  1361.         hidden_active = FALSE;
  1362.     }
  1363. #endif /* not LITE */
  1364. }
  1365.  
  1366. /* plot3d_impulses:
  1367.  * Plot the surfaces in IMPULSES style
  1368.  */
  1369. static plot3d_impulses(plot)
  1370.     struct surface_points *plot;
  1371. {
  1372.     int i;                /* point index */
  1373.     int x,y,x0,y0;            /* point in terminal coordinates */
  1374.     struct iso_curve *icrvs = plot->iso_crvs;
  1375.  
  1376.     while ( icrvs ) {
  1377.     struct coordinate GPHUGE *points = icrvs->points;
  1378.  
  1379.     for (i = 0; i < icrvs->p_count; i++) {
  1380.         if (real_z_max3d<points[i].z)
  1381.         real_z_max3d=points[i].z;
  1382.         if (real_z_min3d>points[i].z)
  1383.         real_z_min3d=points[i].z;
  1384.  
  1385.         map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1386.         map3d_xy(points[i].x, points[i].y, z_min3d, &x0, &y0);
  1387.  
  1388.         clip_move(x0,y0);
  1389.         clip_vector(x,y);
  1390.     }
  1391.  
  1392.     icrvs = icrvs->next;
  1393.     }
  1394. }
  1395.  
  1396. /* plot3d_lines:
  1397.  * Plot the surfaces in LINES style
  1398.  */
  1399. /* We want to always draw the lines in the same direction, otherwise when
  1400.    we draw an adjacent box we might get the line drawn a little differently
  1401.    and we get splotches.  */
  1402.  
  1403. #ifndef LITE
  1404.  
  1405. static int zsort( r1, r2)
  1406. int * r1;
  1407. int * r2;
  1408. {
  1409.   int z1, z2;
  1410.   z1 = nodes[*r1].z;
  1411.   z2 = nodes[*r2].z;
  1412.   if (z1 < z2) return 1;
  1413.   if (z1 == z2) return 0;
  1414.   return -1;
  1415. }
  1416. #define TESTBOX(X,Y)                    \
  1417.   if(X<xmin_box) xmin_box = X;                \
  1418.   if(X>xmax_box) xmax_box = X;                \
  1419.   if(Y<ymin_box) ymin_box = Y;                \
  1420.   if(Y>ymax_box) ymax_box = Y;
  1421. /* Usefull macro to help us figure out which side of the surface we are on */
  1422. #define XPRD(I,J,K)                     \
  1423.   ((nodes[I].x-nodes[J].x)*(nodes[J].y-nodes[K].y) -    \
  1424.   (nodes[I].y-nodes[J].y)*(nodes[J].x-nodes[K].x))
  1425. #define MAYBE_LINEPOINT(J)                        \
  1426.     if((nodes[J].flag & 0x20) != 0) {                \
  1427.       x = nodes[J].x;                        \
  1428.       y = nodes[J].y;                        \
  1429.       nodes[J].flag -= 0x20;                    \
  1430.       if (!clip_point(x,y) &&                     \
  1431.       !IFSET(XREDUCE(x)-XREDUCE(xleft),YREDUCE(y)-YREDUCE(ybot))) \
  1432.     (*t->point)(x,y, plot_info[nplot].point_type);        \
  1433.     };
  1434.  
  1435. struct surface_plots{
  1436.   int above_color;
  1437.   int below_color;
  1438.   int row_offset;
  1439.   int point_type;
  1440. };
  1441. /* All of the plots coming into this routine are assumed to have grid
  1442.    topology.  */
  1443.  
  1444. static plot3d_hidden(plots, pcount)
  1445.      struct surface_points *plots;
  1446.      int pcount;
  1447. {
  1448.   struct surface_points *this_plot;
  1449.   long int i, j;
  1450.   int nplot;
  1451.   long int x,y,z ,nseg, ncrv, ncrv1;        /* point in terminal coordinates */
  1452. #ifdef AMIGA_SC_6_1
  1453.   unsigned short int * cpnt;
  1454. #else /* !AMIGA_SC_6_1 */
  1455.   short int * cpnt;
  1456. #endif /* !AMIGA_SC_6_1 */
  1457.   short int  mask1, mask2;
  1458.   long int indx1, indx2, k, m;
  1459.   short int xmin_box, xmax_box, ymin_box, ymax_box;
  1460.   struct surface_plots * plot_info;
  1461.   int row_offset, nnode;
  1462.   short int y_malloc;  /* Amount of space we need for one vertical row of
  1463.                           bitmap, and byte offset of first used element */
  1464.   struct termentry *t = &term_tbl[term];
  1465.   struct iso_curve *icrvs;
  1466.   int current_style = 0x7fff;  /* Current line style */
  1467.   int surface;
  1468.   nnode = 0;
  1469.   nseg = 0;
  1470.   nplot = 0;
  1471.   this_plot = plots;
  1472.  
  1473.   for (surface = 0;
  1474.        surface < pcount;
  1475.        this_plot = this_plot->next_sp, surface++) {
  1476.     nplot++;
  1477.     icrvs = plots->iso_crvs;
  1478.     icrvs = plots->iso_crvs;
  1479.     if(this_plot->plot_type == FUNC3D) {
  1480.         for(icrvs = this_plot->iso_crvs,ncrv=0;icrvs;icrvs=icrvs->next,ncrv++) { };
  1481.  /*      if(this_plot->has_grid_topology) ncrv >>= 1; */
  1482.     };
  1483.     if(this_plot->plot_type == DATA3D)
  1484.        ncrv = this_plot->num_iso_read;
  1485.     nnode += ncrv * (this_plot->iso_crvs->p_count);
  1486. /*    for(icrvs = this_plot->iso_crvs,ncrv=0;icrvs;icrvs=icrvs->next,ncrv++) { };
  1487.     nnode += ncrv * (this_plot->iso_crvs->p_count); */
  1488.     switch(this_plot->plot_style) {
  1489.     case ERRORBARS:
  1490.     case DOTS:
  1491.     case POINTSTYLE:
  1492.     case LINESPOINTS:
  1493.       nseg += (ncrv) * (this_plot->iso_crvs->p_count);
  1494.       break;
  1495.     case LINES:
  1496.       nseg += (ncrv-1) * (this_plot->iso_crvs->p_count-1);
  1497.       break;
  1498.     case IMPULSES:
  1499.       /* There will be two nodes for each segment */
  1500.       nnode += ncrv * (this_plot->iso_crvs->p_count);
  1501.       nseg += (ncrv) * (this_plot->iso_crvs->p_count);
  1502.       break;
  1503.     }
  1504.   };
  1505.   boxlist = (int *) alloc((unsigned long)sizeof(int)*nseg, "hidden");
  1506.   nodes = (struct pnts *) alloc((unsigned long)sizeof(struct pnts)*nnode, "hidden");
  1507.   plot_info = (struct surface_plots *) alloc((unsigned long)sizeof(struct surface_plots)*nplot,"hidden");
  1508.   nnode = 0;
  1509.   nseg = 0;
  1510.   nplot = 0;
  1511.   this_plot = plots;
  1512.   hidden_no_update = FALSE;
  1513.  
  1514.   if ( hidden3d && draw_surface)
  1515.     for (surface = 0;
  1516.      surface < pcount;
  1517.      this_plot = this_plot->next_sp, surface++) {
  1518.       (*t->linetype)(this_plot->line_type);
  1519.       hidden_line_type_above = this_plot->line_type;
  1520.         hidden_line_type_below = this_plot->line_type + 1;
  1521.     if(this_plot->plot_type == FUNC3D) {
  1522.       for(icrvs = this_plot->iso_crvs,ncrv=0;icrvs;icrvs=icrvs->next,ncrv++) { };
  1523. /*      if(this_plot->has_grid_topology) ncrv >>= 1; */
  1524.     };
  1525.     if(this_plot->plot_type == DATA3D)
  1526.       ncrv = this_plot->num_iso_read;
  1527.       icrvs = this_plot->iso_crvs;
  1528.       ncrv1 = ncrv;
  1529.       ncrv = 0;
  1530.       while ( icrvs) {
  1531.     struct coordinate GPHUGE *points = icrvs->points;
  1532.     for (i = 0; i < icrvs->p_count; i++) {
  1533.       map3d_xy(points[i].x, points[i].y, points[i].z,&nodes[nnode].x,&nodes[nnode].y);
  1534.       nodes[nnode].z = map3d_z(points[i].x, points[i].y, points[i].z);
  1535.       nodes[nnode].flag = (i==0 ? 1 : 0) + (ncrv == 0 ? 2 : 0) +
  1536.         (i == icrvs->p_count-1 ? 4 : 0) + (ncrv == ncrv1-1 ? 8 : 0);
  1537.       nodes[nnode].nplot = nplot;
  1538.       nodes[nnode].style_used = -1000; /* indicates no style */
  1539.       switch(this_plot->plot_style) {
  1540.       case LINESPOINTS:
  1541.         if(i < icrvs->p_count-1 && ncrv < ncrv1-1)
  1542.           nodes[nnode].flag |= 0x30;
  1543.         else
  1544.           nodes[nnode].flag |= 0x20;
  1545.         boxlist[nseg++] = nnode++;
  1546.         break;
  1547.       case LINES:
  1548.         if(i < icrvs->p_count-1 && ncrv < ncrv1-1)
  1549.           {
  1550.         nodes[nnode].flag |= 0x10;
  1551.         boxlist[nseg++] = nnode++;
  1552.           }
  1553.         else
  1554.           nnode++;
  1555.         break;
  1556.       case ERRORBARS:
  1557.       case POINTSTYLE:
  1558.       case DOTS:
  1559.         nodes[nnode].flag |= 0x40;
  1560.         boxlist[nseg++] = nnode++;
  1561.         break;
  1562.       case IMPULSES:
  1563.         nodes[nnode].flag |= 0x80;
  1564.         boxlist[nseg++] = nnode++;
  1565.         map3d_xy(points[i].x, points[i].y, z_min3d, &nodes[nnode].x,&nodes[nnode].y);
  1566.         nodes[nnode].z = map3d_z(points[i].x, points[i].y, z_min3d);
  1567.         nnode++;
  1568.         break;
  1569.         break;
  1570.       }
  1571.     }
  1572.     icrvs = icrvs->next;
  1573.     ncrv++;
  1574.     if(ncrv == ncrv1) break;
  1575.       }
  1576.       /* Next we go through all of the boxes, and substitute the average z value
  1577.      for the box for the z value of the corner node */
  1578.       plot_info[nplot].above_color = this_plot->line_type;
  1579.       plot_info[nplot].below_color = this_plot->line_type+1;
  1580.       plot_info[nplot].point_type =
  1581.     ((this_plot->plot_style == DOTS) ? -1 : this_plot->point_type);
  1582.       plot_info[nplot++].row_offset = this_plot->iso_crvs->p_count;
  1583.     }
  1584.       for(i=0; i<nseg; i++){
  1585.     j = boxlist[i];
  1586.     if ((nodes[j].flag & 0x80) != 0) {
  1587.       nodes[j].z = (nodes[j].z < nodes[j+1].z ? nodes[j].z : nodes[j+1].z);
  1588.       continue;
  1589.     };
  1590.     if ((nodes[j].flag & 0x10) == 0) continue;
  1591.     row_offset = plot_info[nodes[j].nplot].row_offset;
  1592.     z = nodes[j].z;
  1593.     if (z < nodes[j+1].z) z = nodes[j+1].z;
  1594.     if (z < nodes[j+row_offset].z) z = nodes[j+row_offset].z;
  1595.     if (z < nodes[j+row_offset+1].z) z = nodes[j+row_offset+1].z;
  1596.       };
  1597.   qsort (boxlist, nseg, sizeof(int), zsort);
  1598.   y_malloc = (2+ (YREDUCE(ytop)>>4) - (YREDUCE(ybot)>>4))*sizeof(short int);
  1599.   for(i=0;i<=(XREDUCE(xright)-XREDUCE(xleft));i++) {
  1600.     ymin_hl[i] = 0x7fff; 
  1601.     ymax_hl[i] = 0;
  1602.   };
  1603.   for(i=0;i<nseg;i++) {
  1604.     j = boxlist[i];
  1605.     nplot = nodes[j].nplot;
  1606.     row_offset = plot_info[nplot].row_offset;
  1607.     if((nodes[j].flag & 0x40) != 0) {
  1608.       x = nodes[j].x;
  1609.       y = nodes[j].y;
  1610.       if (!clip_point(x,y) &&
  1611.       !IFSET(XREDUCE(x)-XREDUCE(xleft),YREDUCE(y)-YREDUCE(ybot)))
  1612.     (*t->point)(x,y, plot_info[nplot].point_type);
  1613.     };
  1614.     if((nodes[j].flag & 0x80) != 0) { /* impulses */
  1615.       clip_move(nodes[j].x,nodes[j].y);
  1616.       clip_vector(nodes[j+1].x,nodes[j+1].y);
  1617.     };
  1618.     if((nodes[j].flag & 0x10) != 0) {
  1619. /* It is possible, and often profitable, to take a quick look and see
  1620.    if the current box is entirely obscured.  If this is the case we will
  1621.    not even bother testing this box any further.  */
  1622.       xmin_box = 0x7fff; 
  1623.       xmax_box = 0;
  1624.       ymin_box = 0x7fff; 
  1625.       ymax_box = 0;
  1626.       TESTBOX(nodes[j].x-xleft,nodes[j].y-ybot);
  1627.       TESTBOX(nodes[j+1].x-xleft,nodes[j+1].y-ybot);
  1628.       TESTBOX(nodes[j+row_offset].x-xleft,nodes[j+row_offset].y-ybot);
  1629.       TESTBOX(nodes[j+row_offset+1].x-xleft,nodes[j+row_offset+1].y-ybot);
  1630.       z=0;
  1631.       if(xmin_box < 0) xmin_box = 0;
  1632.       if(ymin_box < 0) ymin_box = 0;
  1633.       if(xmax_box > xright-xleft) xmax_box = xright-xleft;
  1634.       if(ymax_box > ytop-ybot) ymax_box = ytop-ybot;
  1635.       /* Now check bitmap.  These coordinates have not been reduced */
  1636.       if(xmin_box <= xmax_box && ymin_box <= ymax_box){
  1637.     ymin_box = YREDUCE(ymin_box);
  1638.     ymax_box = YREDUCE(ymax_box);
  1639.     xmin_box = XREDUCE(xmin_box);
  1640.     xmax_box = XREDUCE(xmax_box);
  1641.     indx1 = ymin_box >> 4;
  1642.     indx2 = ymax_box >> 4;
  1643.     mask1 = 0xffff << (ymin_box & 0x0f);
  1644.     mask2 = 0xffff >> (0x0f-(ymax_box & 0x0f));
  1645.     for(m=xmin_box;m<=xmax_box;m++) {
  1646.       if(pnt[m] == 0) {z++; break;};
  1647.       cpnt = pnt[m] + indx1;
  1648.       if(indx1 == indx2){
  1649.         if((*cpnt & mask1 & mask2) != (mask1 & mask2)) {z++; break;}
  1650.       } else {
  1651.         if((*cpnt++ & mask1) != mask1) {z++; break;}
  1652.         k = indx1+1;
  1653.         while (k != indx2) {
  1654.           if((unsigned short)*cpnt++ != 0xffff) {z++; break;}
  1655.           k++;
  1656.         };
  1657.         if((*cpnt++ & mask2) != mask2) {z++; break;}
  1658.       };
  1659.     };
  1660.       };
  1661.       /* z is 0 if all of the pixels used by the current box are already covered.
  1662.      No point in proceeding, so we just skip all further processing of this
  1663.      box. */
  1664.       if(!z) continue;
  1665.       /* Now we need to figure out whether we are looking at the top or the
  1666.      bottom of the square.  A simple cross product will tell us this.
  1667.      If the square is really distorted then this will not be accurate,
  1668.      but in such cases we would actually be seeing both sides at the same
  1669.      time.  We choose the vertex with the largest z component to
  1670.      take the cross product at.  */
  1671.       {
  1672.     int z1, z2 ,z3, z4;
  1673.     z1 = XPRD(j+row_offset,j,j+1);
  1674.     z2 = XPRD(j,j+1,j+1+row_offset);
  1675.     z3 = XPRD(j+1,j+row_offset+1,j+row_offset);
  1676.     z4 = XPRD(j+row_offset+1,j+row_offset,j);
  1677.     z=0;
  1678.     z += (z1 > 0 ? 1 : -1);
  1679.     z += (z2 > 0 ? 1 : -1);
  1680.     z += (z3 > 0 ? 1 : -1);
  1681.     z += (z4 > 0 ? 1 : -1);
  1682.     /* See if the box is uniformly one side or another. */
  1683.     if(z != 4 && z != -4) {
  1684. /* It isn't.  Now find the corner of the box with the largest z value that
  1685.    has already been plotted, and use the same style used for that node.  */
  1686.       k = -1000;
  1687.       x = -32768;
  1688.       if (nodes[j].z > x && nodes[j].style_used !=-1000) {
  1689.         k = nodes[j].style_used;
  1690.         x = nodes[j].z;
  1691.       };
  1692.       if (nodes[j+1].z > x && nodes[j+1].style_used !=-1000) {
  1693.         k = nodes[j+1].style_used;
  1694.         x = nodes[j+1].z;
  1695.       };
  1696.       if (nodes[j+row_offset+1].z > x && nodes[j+row_offset+1].style_used !=-1000) {
  1697.         k = nodes[j+row_offset+1].style_used;
  1698.         x = nodes[j+row_offset+1].z;
  1699.       };
  1700.       if (nodes[j+row_offset].z > x && nodes[j+row_offset].style_used !=-1000) {
  1701.         k = nodes[j+row_offset].style_used;
  1702.         x = nodes[j+row_offset].z;
  1703.       };
  1704.       if( k != -1000){
  1705.         z = 0; /* To defeat the logic to come.  */
  1706.         current_style = k;
  1707.         (*t->linetype)(current_style);
  1708.       };
  1709.     };
  1710.     /* If k == -1000 then no corner found.  I guess it does not matter.  */
  1711.       };
  1712.       if(z > 0 && current_style != plot_info[nplot].above_color) {
  1713.     current_style = plot_info[nplot].above_color;
  1714.     (*t->linetype)(current_style);
  1715.       };
  1716.       if(z < 0 && current_style != plot_info[nplot].below_color) {
  1717.     current_style = plot_info[nplot].below_color;
  1718.     (*t->linetype)(current_style);
  1719.       };
  1720.       xmin_hl = (sizeof(xleft) == 4 ? 0x7fffffff : 0x7fff ); 
  1721.       xmax_hl = 0;
  1722.       clip_move(nodes[j].x,nodes[j].y);
  1723.       clip_vector(nodes[j+1].x,nodes[j+1].y);
  1724.       clip_vector(nodes[j+row_offset+1].x,nodes[j+row_offset+1].y);
  1725.       clip_vector(nodes[j+row_offset].x,nodes[j+row_offset].y);
  1726.       clip_vector(nodes[j].x,nodes[j].y);
  1727.       nodes[j].style_used = current_style;
  1728.       nodes[j+1].style_used = current_style;
  1729.       nodes[j+row_offset+1].style_used = current_style;
  1730.       nodes[j+row_offset].style_used = current_style;
  1731.       MAYBE_LINEPOINT(j);
  1732.       MAYBE_LINEPOINT(j+1);
  1733.       MAYBE_LINEPOINT(j+row_offset+1);
  1734.       MAYBE_LINEPOINT(j+row_offset);
  1735.       if( xmin_hl < 0 || xmax_hl > XREDUCE(xright)-XREDUCE(xleft))
  1736.     int_error("Logic error #3 in hidden line",NO_CARET);
  1737.       /* now mark the area as being filled in the bitmap.  These coordinates
  1738.          have already been reduced. */
  1739.       if (xmin_hl < xmax_hl)
  1740.     for(j=xmin_hl;j<=xmax_hl;j++) {
  1741.       if (ymin_hl[j] == 0x7fff) 
  1742.         int_error("Logic error #2 in hidden line",NO_CARET);
  1743.       if(pnt[j] == 0) {
  1744.         pnt[j] = (short int *) alloc((unsigned long)y_malloc,"hidden");
  1745.         bzero(pnt[j],y_malloc);
  1746.       };
  1747.       if(ymin_hl[j] < 0 || ymax_hl[j] > YREDUCE(ytop)-YREDUCE(ybot))
  1748.         int_error("Logic error #1 in hidden line",NO_CARET);
  1749. /* this shift is wordsize dependent */
  1750.       indx1 = ymin_hl[j] >> 4;
  1751.       indx2 = ymax_hl[j] >> 4;
  1752.       mask1 = 0xffff << (ymin_hl[j] & 0xf);
  1753.       mask2 = 0xffff >> (0xf-(ymax_hl[j] & 0xf));
  1754.       cpnt = pnt[j] + indx1;
  1755.       if(indx1 == indx2){
  1756.         *cpnt |= (mask1 & mask2);
  1757.       } else {
  1758.         *cpnt++ |= mask1;
  1759.         k = indx1+1;
  1760.         while (k != indx2) {
  1761.           *cpnt++ = 0xffff; 
  1762.           k++;
  1763.         };
  1764.         *cpnt |= mask2;
  1765.       };
  1766.       ymin_hl[j]=0x7fff; 
  1767.       ymax_hl[j]=0;
  1768.     };
  1769.     };
  1770.   };
  1771.   free(nodes);
  1772.   free(boxlist);
  1773.   free(plot_info);
  1774. }
  1775.  
  1776. #endif /* not LITE */
  1777.  
  1778. static plot3d_lines(plot)
  1779.     struct surface_points *plot;
  1780. {
  1781.     int i;
  1782.     int x,y;                /* point in terminal coordinates */
  1783.     struct iso_curve *icrvs = plot->iso_crvs;
  1784.     struct coordinate GPHUGE *points;
  1785.  
  1786. #ifndef LITE
  1787. /* These are handled elsewhere.  */
  1788.     if (plot->has_grid_topology && hidden3d)
  1789.     return(0);
  1790. #endif /* not LITE */
  1791.  
  1792.     while (icrvs) {
  1793.  
  1794.     for (i = 0, points = icrvs->points; i < icrvs->p_count; i++) {
  1795.         if (real_z_max3d<points[i].z)
  1796.         real_z_max3d=points[i].z;
  1797.         if (real_z_min3d>points[i].z)
  1798.         real_z_min3d=points[i].z;
  1799.  
  1800.         map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1801.  
  1802.         if (i > 0)
  1803.         clip_vector(x,y);
  1804.         else
  1805.         clip_move(x,y);
  1806.     }
  1807.  
  1808.     icrvs = icrvs->next;
  1809.     }
  1810. }
  1811.  
  1812. /* plot3d_points:
  1813.  * Plot the surfaces in POINTSTYLE style
  1814.  */
  1815. static plot3d_points(plot)
  1816.     struct surface_points *plot;
  1817. {
  1818.     int i,x,y;
  1819.     struct termentry *t = &term_tbl[term];
  1820.     struct iso_curve *icrvs = plot->iso_crvs;
  1821.  
  1822.     while ( icrvs ) {
  1823.     struct coordinate GPHUGE *points = icrvs->points;
  1824.  
  1825.     for (i = 0; i < icrvs->p_count; i++) {
  1826.         if (real_z_max3d<points[i].z)
  1827.         real_z_max3d=points[i].z;
  1828.         if (real_z_min3d>points[i].z)
  1829.         real_z_min3d=points[i].z;
  1830.  
  1831.         map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1832.  
  1833.         if (!clip_point(x,y))
  1834.         (*t->point)(x,y, plot->point_type);
  1835.     }
  1836.  
  1837.     icrvs = icrvs->next;
  1838.     }
  1839. }
  1840.  
  1841. /* plot3d_dots:
  1842.  * Plot the surfaces in DOTS style
  1843.  */
  1844. static plot3d_dots(plot)
  1845.     struct surface_points *plot;
  1846. {
  1847.     int i,x,y;
  1848.     struct termentry *t = &term_tbl[term];
  1849.     struct iso_curve *icrvs = plot->iso_crvs;
  1850.  
  1851.     while ( icrvs ) {
  1852.     struct coordinate GPHUGE *points = icrvs->points;
  1853.  
  1854.         for (i = 0; i < icrvs->p_count; i++) {
  1855.         if (real_z_max3d<points[i].z)
  1856.         real_z_max3d=points[i].z;
  1857.         if (real_z_min3d>points[i].z)
  1858.             real_z_min3d=points[i].z;
  1859.  
  1860.             map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1861.  
  1862.             if (!clip_point(x,y))
  1863.         (*t->point)(x,y, -1);
  1864.         }
  1865.  
  1866.     icrvs = icrvs->next;
  1867.     }
  1868. }
  1869.  
  1870. /* cntr3d_impulses:
  1871.  * Plot a surface contour in IMPULSES style
  1872.  */
  1873. static cntr3d_impulses(cntr, plot)
  1874.     struct gnuplot_contours *cntr;
  1875.     struct surface_points *plot;
  1876. {
  1877.     int i;                /* point index */
  1878.     int x,y,x0,y0;            /* point in terminal coordinates */
  1879.  
  1880.     if (draw_contour == CONTOUR_SRF || draw_contour == CONTOUR_BOTH) {
  1881.     for (i = 0; i < cntr->num_pts; i++) {
  1882.         if (real_z_max3d<cntr->coords[i].z)
  1883.         real_z_max3d=cntr->coords[i].z;
  1884.         if (real_z_min3d>cntr->coords[i].z)
  1885.         real_z_min3d=cntr->coords[i].z;
  1886.  
  1887.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  1888.              &x, &y);
  1889.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, z_min3d,
  1890.              &x0, &y0);
  1891.  
  1892.         clip_move(x0,y0);
  1893.         clip_vector(x,y);
  1894.     }
  1895.     }
  1896.     else
  1897.     cntr3d_points(cntr, plot);   /* Must be on base grid, so do points. */
  1898. }
  1899.  
  1900. /* cntr3d_lines:
  1901.  * Plot a surface contour in LINES style
  1902.  */
  1903. static cntr3d_lines(cntr)
  1904.     struct gnuplot_contours *cntr;
  1905. {
  1906.     int i;                /* point index */
  1907.     int x,y;                /* point in terminal coordinates */
  1908.  
  1909.     if (draw_contour == CONTOUR_SRF || draw_contour == CONTOUR_BOTH) {
  1910.     for (i = 0; i < cntr->num_pts; i++) {
  1911.         if (real_z_max3d<cntr->coords[i].z)
  1912.         real_z_max3d=cntr->coords[i].z;
  1913.         if (real_z_min3d>cntr->coords[i].z)
  1914.         real_z_min3d=cntr->coords[i].z;
  1915.  
  1916.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  1917.                  &x, &y);
  1918.  
  1919.              if (i > 0) {
  1920.                  clip_vector(x,y);
  1921.                  if(i == 1) suppressMove = TRUE;
  1922.              } else {
  1923.                  clip_move(x,y);
  1924.              }
  1925.         }
  1926.     }
  1927.      suppressMove = FALSE;  /* beginning a new contour level, so moveto() required */
  1928.  
  1929.     if (draw_contour == CONTOUR_BASE || draw_contour == CONTOUR_BOTH) {
  1930.     for (i = 0; i < cntr->num_pts; i++) {
  1931.         if (real_z_max3d<cntr->coords[i].z)
  1932.         real_z_max3d=cntr->coords[i].z;
  1933.         if (real_z_min3d>cntr->coords[i].z)
  1934.         real_z_min3d=cntr->coords[i].z;
  1935.  
  1936.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, z_min3d,
  1937.                  &x, &y);
  1938.  
  1939.              if (i > 0) {
  1940.                  clip_vector(x,y);
  1941.                  if(i == 1) suppressMove = TRUE;
  1942.              } else {
  1943.                  clip_move(x,y);
  1944.              }
  1945.          }
  1946.      }
  1947.      suppressMove = FALSE;  /* beginning a new contour level, so moveto() required */
  1948. }
  1949.  
  1950. /* cntr3d_points:
  1951.  * Plot a surface contour in POINTSTYLE style
  1952.  */
  1953. static cntr3d_points(cntr, plot)
  1954.     struct gnuplot_contours *cntr;
  1955.     struct surface_points *plot;
  1956. {
  1957.     int i;
  1958.     int x,y;
  1959.     struct termentry *t = &term_tbl[term];
  1960.  
  1961.     if (draw_contour == CONTOUR_SRF || draw_contour == CONTOUR_BOTH) {
  1962.     for (i = 0; i < cntr->num_pts; i++) {
  1963.         if (real_z_max3d<cntr->coords[i].z)
  1964.         real_z_max3d=cntr->coords[i].z;
  1965.         if (real_z_min3d>cntr->coords[i].z)
  1966.         real_z_min3d=cntr->coords[i].z;
  1967.  
  1968.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  1969.                  &x, &y);
  1970.  
  1971.         if (!clip_point(x,y))
  1972.         (*t->point)(x,y, plot->point_type);
  1973.         }
  1974.     }
  1975.  
  1976.     if (draw_contour == CONTOUR_BASE || draw_contour == CONTOUR_BOTH) {
  1977.     for (i = 0; i < cntr->num_pts; i++) {
  1978.         if (real_z_max3d<cntr->coords[i].z)
  1979.         real_z_max3d=cntr->coords[i].z;
  1980.         if (real_z_min3d>cntr->coords[i].z)
  1981.         real_z_min3d=cntr->coords[i].z;
  1982.  
  1983.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, z_min3d,
  1984.                  &x, &y);
  1985.  
  1986.         if (!clip_point(x,y))
  1987.         (*t->point)(x,y, plot->point_type);
  1988.         }
  1989.     }
  1990. }
  1991.  
  1992. /* cntr3d_dots:
  1993.  * Plot a surface contour in DOTS style
  1994.  */
  1995. static cntr3d_dots(cntr)
  1996.     struct gnuplot_contours *cntr;
  1997. {
  1998.     int i;
  1999.     int x,y;
  2000.     struct termentry *t = &term_tbl[term];
  2001.  
  2002.     if (draw_contour == CONTOUR_SRF || draw_contour == CONTOUR_BOTH) {
  2003.     for (i = 0; i < cntr->num_pts; i++) {
  2004.         if (real_z_max3d<cntr->coords[i].z)
  2005.         real_z_max3d=cntr->coords[i].z;
  2006.         if (real_z_min3d>cntr->coords[i].z)
  2007.         real_z_min3d=cntr->coords[i].z;
  2008.  
  2009.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  2010.                  &x, &y);
  2011.  
  2012.         if (!clip_point(x,y))
  2013.         (*t->point)(x,y, -1);
  2014.         }
  2015.     }
  2016.  
  2017.     if (draw_contour == CONTOUR_BASE || draw_contour == CONTOUR_BOTH) {
  2018.     for (i = 0; i < cntr->num_pts; i++) {
  2019.         if (real_z_max3d<cntr->coords[i].z)
  2020.         real_z_max3d=cntr->coords[i].z;
  2021.         if (real_z_min3d>cntr->coords[i].z)
  2022.         real_z_min3d=cntr->coords[i].z;
  2023.  
  2024.             map3d_xy(cntr->coords[i].x, cntr->coords[i].y, z_min3d,
  2025.                  &x, &y);
  2026.  
  2027.         if (!clip_point(x,y))
  2028.         (*t->point)(x,y, -1);
  2029.         }
  2030.     }
  2031. }
  2032.  
  2033. static update_extrema_pts(ix, iy, min_sx_x, min_sx_y, min_sy_x, min_sy_y,
  2034.               x, y)
  2035.     int ix, iy, *min_sx_x, *min_sx_y, *min_sy_x, *min_sy_y;
  2036.     double x, y;
  2037. {
  2038.  
  2039.     if (*min_sx_x > ix + 2 ||         /* find (bottom) left corner of grid */
  2040.     (abs(*min_sx_x - ix) <= 2 && *min_sx_y > iy)) {
  2041.     *min_sx_x = ix;
  2042.     *min_sx_y = iy;
  2043.     min_sx_ox = x;
  2044.     min_sx_oy = y;
  2045.     }
  2046.     if (*min_sy_y > iy + 2 ||         /* find bottom (right) corner of grid */
  2047.     (abs(*min_sy_y - iy) <= 2 && *min_sy_x < ix)) {
  2048.     *min_sy_x = ix;
  2049.     *min_sy_y = iy;
  2050.     min_sy_ox = x;
  2051.     min_sy_oy = y;
  2052.     }
  2053. }
  2054.  
  2055. #endif /* THINK_C_3 */
  2056.  
  2057.  
  2058. #ifdef THINK_P4
  2059.  
  2060. /* Draw the bottom grid for the parametric case. */
  2061. static draw_parametric_grid(plot)
  2062.     struct surface_points *plot;
  2063. {
  2064.     int i,ix,iy,            /* point in terminal coordinates */
  2065.     min_sx_x = 10000,min_sx_y = 10000,min_sy_x = 10000,min_sy_y = 10000,
  2066.         grid_iso_1 = plot->plot_type == DATA3D && plot->has_grid_topology ?
  2067.                     plot->iso_crvs->p_count : iso_samples_1,
  2068.         grid_iso_2 = plot->plot_type == DATA3D && plot->has_grid_topology ?
  2069.                     plot->num_iso_read : iso_samples_2;
  2070.     double x,y,dx,dy;
  2071.  
  2072.     if (grid && plot->has_grid_topology) {
  2073.  
  2074.     /* fix grid lines to tic marks, D. Taber, 02-01-93 */
  2075.     if(xtics && xticdef.type == TIC_SERIES) {
  2076.         dx = xticdef.def.series.incr;
  2077.         x = xticdef.def.series.start;
  2078.         grid_iso_1 = 1 + (xticdef.def.series.end - x) / dx;
  2079.     } else {
  2080.         x = x_min3d;
  2081.     dx = (x_max3d-x_min3d) / (grid_iso_1-1);
  2082.     }
  2083.  
  2084.     if(ytics && yticdef.type == TIC_SERIES) {
  2085.         dy = yticdef.def.series.incr;
  2086.         y = yticdef.def.series.start;
  2087.         grid_iso_2 = 1 + (yticdef.def.series.end - y) / dy;
  2088.     } else {
  2089.         y = y_min3d;
  2090.     dy = (y_max3d-y_min3d) / (grid_iso_2-1);
  2091.     }
  2092.  
  2093.     for (i = 0; i < grid_iso_2; i++) {
  2094.             if (i == 0 || i == grid_iso_2-1)            
  2095.             setlinestyle(-2);
  2096.         else
  2097.             setlinestyle(-1);
  2098.         map3d_xy(x_min3d, y, z_min3d, &ix, &iy);
  2099.         clip_move(ix,iy);
  2100.         update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  2101.                    &min_sy_x,&min_sy_y,x_min3d,y);
  2102.  
  2103.         map3d_xy(x_max3d, y, z_min3d, &ix, &iy);
  2104.         clip_vector(ix,iy);
  2105.         update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  2106.                    &min_sy_x,&min_sy_y,x_max3d,y);
  2107.  
  2108.         y += dy;
  2109.     }
  2110.  
  2111.     for (i = 0; i < grid_iso_1; i++) {
  2112.             if (i == 0 || i == grid_iso_1-1)
  2113.             setlinestyle(-2);
  2114.         else
  2115.             setlinestyle(-1);
  2116.         map3d_xy(x, y_min3d, z_min3d, &ix, &iy);
  2117.         clip_move(ix,iy);
  2118.         update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  2119.                    &min_sy_x,&min_sy_y,x,y_min3d);
  2120.  
  2121.         map3d_xy(x, y_max3d, z_min3d, &ix, &iy);
  2122.         clip_vector(ix,iy);
  2123.         update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  2124.                    &min_sy_x,&min_sy_y,x,y_max3d);
  2125.  
  2126.         x += dx;
  2127.     }
  2128.     }
  2129.     else {
  2130.     setlinestyle(-2);
  2131.  
  2132.     map3d_xy(x_min3d, y_min3d, z_min3d, &ix, &iy);
  2133.     clip_move(ix,iy);
  2134.     update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  2135.                &min_sy_x,&min_sy_y,x_min3d,y_min3d);
  2136.  
  2137.     map3d_xy(x_max3d, y_min3d, z_min3d, &ix, &iy);
  2138.     clip_vector(ix,iy);
  2139.     update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  2140.                &min_sy_x,&min_sy_y,x_max3d,y_min3d);
  2141.  
  2142.     map3d_xy(x_max3d, y_max3d, z_min3d, &ix, &iy);
  2143.     clip_vector(ix,iy);
  2144.     update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  2145.                &min_sy_x,&min_sy_y,x_max3d,y_max3d);
  2146.  
  2147.     map3d_xy(x_min3d, y_max3d, z_min3d, &ix, &iy);
  2148.     clip_vector(ix,iy);
  2149.     update_extrema_pts(ix,iy,&min_sx_x,&min_sx_y,
  2150.                &min_sy_x,&min_sy_y,x_min3d,y_max3d);
  2151.  
  2152.  
  2153.     map3d_xy(x_min3d, y_min3d, z_min3d, &ix, &iy);
  2154.     clip_vector(ix,iy);
  2155.     }
  2156. }
  2157.  
  2158. /* Draw the bottom grid for non parametric case. */
  2159. static draw_non_param_grid(plot)
  2160.     struct surface_points *plot;
  2161. {
  2162.     int i,is_boundary=TRUE,crv_count=0,
  2163.     x,y,                /* point in terminal coordinates */
  2164.     min_sx_x = 10000,min_sx_y = 10000,min_sy_x = 10000,min_sy_y = 10000,
  2165.         grid_iso = plot->plot_type == DATA3D && plot->has_grid_topology ?
  2166.                     plot->num_iso_read : iso_samples_2;
  2167.     struct iso_curve *icrvs = plot->iso_crvs;
  2168.  
  2169.     while ( icrvs ) {
  2170.     struct coordinate GPHUGE *points = icrvs->points;
  2171.     int saved_hidden_active = hidden_active;
  2172.     int z1 = map3d_z(points[0].x, points[0].y, 0.0),
  2173.            z2 = map3d_z(points[icrvs->p_count-1].x,
  2174.                             points[icrvs->p_count-1].y, 0.0);
  2175.  
  2176.     for (i = 0; i < icrvs->p_count; i += icrvs->p_count-1) {
  2177.         map3d_xy(points[i].x, points[i].y, z_min3d, &x, &y);
  2178.         if (is_boundary) {
  2179.         setlinestyle(-2);
  2180.         }
  2181.         else {
  2182.             setlinestyle(-1);
  2183.         }
  2184.  
  2185.         if (i > 0) {
  2186.             clip_vector(x,y);
  2187.         }
  2188.         else {
  2189.             clip_move(x,y);
  2190.         }
  2191.  
  2192.         if (draw_surface &&
  2193.             is_boundary &&
  2194.             (i == 0 || i == icrvs->p_count-1)) {
  2195.             int x1,y1;            /* point in terminal coordinates */
  2196.  
  2197.         /* Draw a vertical line to surface corner from grid corner. */
  2198.             map3d_xy(points[i].x, points[i].y, points[i].z, &x1, &y1);
  2199. #ifndef LITE
  2200.             if (hidden3d) {
  2201.             if ((i == 0 && z1 > z2) ||
  2202.                 (i == icrvs->p_count-1 && z2 > z1)) {
  2203.                 hidden_active = FALSE; /* This one is always visible. */
  2204.             }                
  2205.             }
  2206. #endif /* not LITE */
  2207.             clip_vector(x1,y1);
  2208.             clip_move(x,y);
  2209.         hidden_active = saved_hidden_active;
  2210.         update_extrema_pts(x,y,&min_sx_x,&min_sx_y, &min_sy_x,&min_sy_y,
  2211.                    points[i].x,points[i].y);
  2212.         }
  2213.     }
  2214.  
  2215.     if (grid) {
  2216.         crv_count++;
  2217.         icrvs = icrvs->next;
  2218.         is_boundary = crv_count == grid_iso - 1 ||
  2219.               crv_count == grid_iso ||
  2220.               (icrvs && icrvs->next == NULL);
  2221.     }
  2222.     else {
  2223.         switch (crv_count++) {
  2224.         case 0:
  2225.             for (i = 0; i < grid_iso - 1; i++)
  2226.             icrvs = icrvs->next;
  2227.             break;
  2228.         case 1:
  2229.             icrvs = icrvs->next;
  2230.             break;
  2231.         case 2:
  2232.             while (icrvs->next)
  2233.             icrvs = icrvs->next;
  2234.             break;
  2235.         case 3:
  2236.             icrvs = NULL;
  2237.             break;
  2238.         }
  2239.         }
  2240.     }
  2241.     if(hidden3d){
  2242.       struct iso_curve *lcrvs = plot->iso_crvs;
  2243.       struct coordinate GPHUGE *points, GPHUGE *lpoints;
  2244.       icrvs = lcrvs;
  2245.       while(lcrvs->next) lcrvs = lcrvs->next;
  2246.       points = icrvs->points;
  2247.       lpoints = lcrvs->points;
  2248.       is_boundary = TRUE;
  2249.       for (i = 0; i < icrvs->p_count; i += (grid ? 1 : icrvs->p_count - 1)) {
  2250.     if ((i == 0) || (i == icrvs->p_count - 1)) {
  2251.       setlinestyle(-2);
  2252.     }
  2253.     else {
  2254.       setlinestyle(-1);
  2255.     }
  2256.     map3d_xy(points[i].x, points[i].y, z_min3d, &x, &y);
  2257.     clip_move(x, y);
  2258.     map3d_xy(lpoints[i].x, lpoints[i].y, z_min3d, &x, &y);
  2259.     clip_vector(x, y);
  2260.       };
  2261.     };
  2262. }
  2263.  
  2264. /* Draw the bottom grid that hold the tic marks for 3d surface. */
  2265. #ifdef THINK_C
  2266. draw_bottom_grid(plot, min_z, max_z)
  2267. #else
  2268. static draw_bottom_grid(plot, min_z, max_z)
  2269. #endif
  2270.     struct surface_points *plot;
  2271.     double min_z, max_z;
  2272. {
  2273.     int x,y;    /* point in terminal coordinates */
  2274.     double xtic,ytic,ztic;
  2275.     struct termentry *t = &term_tbl[term];
  2276.  
  2277.     xtic = make_3dtics(x_min3d,x_max3d,'x',is_log_x,base_log_x);
  2278.     ytic = make_3dtics(y_min3d,y_max3d,'y',is_log_y,base_log_y);
  2279.     ztic = make_3dtics(min_z,max_z,'z',is_log_z,base_log_z);
  2280.  
  2281.     if (draw_border)
  2282.     if (parametric || !plot->has_grid_topology)
  2283.         draw_parametric_grid(plot);
  2284.     else
  2285.         draw_non_param_grid(plot);
  2286.  
  2287.     setlinestyle(-2); /* border linetype */
  2288.  
  2289. /* label x axis tics */
  2290.     if (xtics && xtic > 0.0) {
  2291.         switch (xticdef.type) {
  2292.             case TIC_COMPUTED:
  2293.          if (x_min3d < x_max3d)
  2294.             draw_3dxtics(xtic * floor(x_min3d/xtic),
  2295.                      xtic,
  2296.                      xtic * ceil(x_max3d/xtic),
  2297.                      min_sy_oy);
  2298.                 else
  2299.             draw_3dxtics(xtic * floor(x_max3d/xtic),
  2300.                      xtic,
  2301.                      xtic * ceil(x_min3d/xtic),
  2302.                      min_sy_oy);
  2303.             break;
  2304.         case TIC_MONTH:
  2305.         draw_month_3dxtics(min_sy_oy);
  2306.         break;
  2307.         case TIC_DAY:
  2308.         draw_day_3dxtics(min_sy_oy);
  2309.         break;
  2310.         case TIC_SERIES:
  2311.         draw_series_3dxtics(xticdef.def.series.start, 
  2312.                     xticdef.def.series.incr, 
  2313.                     xticdef.def.series.end,
  2314.                     min_sy_oy);
  2315.         break;
  2316.         case TIC_USER:
  2317.         draw_set_3dxtics(xticdef.def.user,
  2318.                  min_sy_oy);
  2319.         break;
  2320.             default:
  2321.             (*t->text)();
  2322.             (void) fflush(outfile);
  2323.             int_error("unknown tic type in xticdef in do_3dplot", NO_CARET);
  2324.             break;        /* NOTREACHED */
  2325.         }
  2326.     }
  2327. /* label y axis tics */
  2328.     if (ytics && (ytic > 0.0)) {
  2329.         switch (yticdef.type) {
  2330.             case TIC_COMPUTED:
  2331.          if (y_min3d < y_max3d) {
  2332.             draw_3dytics(ytic * floor(y_min3d/ytic),
  2333.                      ytic,
  2334.                      ytic * ceil(y_max3d/ytic),
  2335.                      min_sy_ox);
  2336.          }else{
  2337.             draw_3dytics(ytic * floor(y_max3d/ytic),
  2338.                      ytic,
  2339.                      ytic * ceil(y_min3d/ytic),
  2340.                      min_sy_ox);
  2341.         }
  2342.             break;
  2343.         case TIC_MONTH:
  2344.         draw_month_3dytics(min_sy_ox);
  2345.         break;
  2346.         case TIC_DAY:
  2347.         draw_day_3dytics(min_sy_ox);
  2348.         break;
  2349.         case TIC_SERIES:
  2350.         draw_series_3dytics(yticdef.def.series.start, 
  2351.                     yticdef.def.series.incr, 
  2352.                     yticdef.def.series.end,
  2353.                     min_sy_ox);
  2354.         break;
  2355.         case TIC_USER:
  2356.         draw_set_3dytics(yticdef.def.user,
  2357.                  min_sy_ox);
  2358.         break;
  2359.             default:
  2360.             (*t->text)();
  2361.             (void) fflush(outfile);
  2362.             int_error("unknown tic type in yticdef in do_3dplot", NO_CARET);
  2363.             break;        /* NOTREACHED */
  2364.         }
  2365.     }
  2366. /* label z axis tics */
  2367.     if (ztics && ztic > 0.0 && (draw_surface ||
  2368.                 draw_contour == CONTOUR_SRF ||
  2369.                 draw_contour == CONTOUR_BOTH)) {
  2370.         switch (zticdef.type) {
  2371.             case TIC_COMPUTED:
  2372.          if (min_z < max_z)
  2373.             draw_3dztics(ztic * floor(min_z/ztic),
  2374.                      ztic,
  2375.                      ztic * ceil(max_z/ztic),
  2376.                  min_sx_ox,
  2377.                      min_sx_oy,
  2378.                      min_z,
  2379.                  max_z);
  2380.                 else
  2381.             draw_3dztics(ztic * floor(max_z/ztic),
  2382.                      ztic,
  2383.                      ztic * ceil(min_z/ztic),
  2384.                      min_sx_ox,
  2385.                  min_sx_oy,
  2386.                      max_z,
  2387.                  min_z);
  2388.             break;
  2389.         case TIC_MONTH:
  2390.         draw_month_3dztics(min_sx_ox,min_sx_oy,min_z,max_z);
  2391.         break;
  2392.         case TIC_DAY:
  2393.         draw_day_3dztics(min_sx_ox,min_sx_oy,min_z,max_z);
  2394.         break;
  2395.         case TIC_SERIES:
  2396.         draw_series_3dztics(zticdef.def.series.start, 
  2397.                     zticdef.def.series.incr, 
  2398.                     zticdef.def.series.end,
  2399.                     min_sx_ox,
  2400.                     min_sx_oy,
  2401.                     min_z,
  2402.                     max_z);
  2403.  
  2404.         break;
  2405.         case TIC_USER:
  2406.         draw_set_3dztics(zticdef.def.user,
  2407.                  min_sx_ox,
  2408.                      min_sx_oy,
  2409.                      min_z,
  2410.                  max_z);
  2411.         break;
  2412.             default:
  2413.             (*t->text)();
  2414.             (void) fflush(outfile);
  2415.             int_error("unknown tic type in zticdef in do_3dplot", NO_CARET);
  2416.             break;        /* NOTREACHED */
  2417.         }
  2418.     }
  2419.  
  2420. /* PLACE XLABEL - along the middle grid X axis */
  2421.     if (strlen(xlabel) > 0) {
  2422.        int x1,y1;
  2423.        double step = apx_eq( min_sy_oy, y_min3d ) ?    (y_max3d-y_min3d)/4
  2424.                               : (y_min3d-y_max3d)/4;
  2425.            map3d_xy((x_min3d+x_max3d)/2,min_sy_oy-step, z_min3d,&x1,&y1);
  2426.        x1 += xlabel_xoffset * t->h_char;
  2427.        y1 += xlabel_yoffset * t->v_char;
  2428.        if ((*t->justify_text)(CENTRE))
  2429.         clip_put_text(x1,y1,xlabel);
  2430.        else
  2431.         clip_put_text(x1 - strlen(xlabel)*(t->h_char)/2,y1,xlabel);
  2432.     }
  2433.  
  2434. /* PLACE YLABEL - along the middle grid Y axis */
  2435.     if (strlen(ylabel) > 0) {
  2436.        int x1,y1;
  2437.        double step = apx_eq( min_sy_ox, x_min3d ) ?    (x_max3d-x_min3d)/4
  2438.                               : (x_min3d-x_max3d)/4;
  2439.            map3d_xy(min_sy_ox-step,(y_min3d+y_max3d)/2,z_min3d,&x1,&y1);
  2440.        x1 += ylabel_xoffset * t->h_char;
  2441.        y1 += ylabel_yoffset * t->v_char;
  2442.        if ((*t->justify_text)(CENTRE))
  2443.         clip_put_text(x1,y1,ylabel);
  2444.        else
  2445.         clip_put_text(x1 - strlen(ylabel)*(t->h_char)/2,y1,ylabel);
  2446.     }
  2447.  
  2448. /* PLACE ZLABEL - along the middle grid Z axis */
  2449.     if (strlen(zlabel) > 0 &&
  2450.         (draw_surface ||
  2451.      draw_contour == CONTOUR_SRF ||
  2452.      draw_contour == CONTOUR_BOTH)) {
  2453.            map3d_xy(min_sx_ox,min_sx_oy,max_z + (max_z-min_z)/4, &x, &y);
  2454.  
  2455.        x += zlabel_xoffset * t->h_char;
  2456.        y += zlabel_yoffset * t->v_char;
  2457.        if ((*t->justify_text)(CENTRE))
  2458.         clip_put_text(x,y,zlabel);
  2459.        else
  2460.         clip_put_text(x - strlen(zlabel)*(t->h_char)/2,y,zlabel);
  2461.     }
  2462. }
  2463.  
  2464. /* DRAW_3DXTICS: draw a regular tic series, x axis */
  2465. static draw_3dxtics(start, incr, end, ypos)
  2466.     double start, incr, end, ypos; /* tic series definition */
  2467.         /* assume start < end, incr > 0 */
  2468. {
  2469.     double ticplace;
  2470.     int ltic;        /* for mini log tics */
  2471.     double lticplace;    /* for mini log tics */
  2472.  
  2473.     end = end + SIGNIF*incr; 
  2474.  
  2475.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  2476.         if (ticplace < start || ticplace > end) continue;
  2477.         xtick(ticplace, xformat, incr, 1.0, ypos);
  2478.         if (is_log_x && incr == 1.0) {
  2479.             /* add mini-ticks to log scale ticmarks */
  2480.             for (ltic = 2; ltic < (int)base_log_x; ltic++) {
  2481.                 lticplace = ticplace+log((double)ltic)/log_base_log_x;
  2482.                 xtick(lticplace, "\0", incr, 0.5, ypos);
  2483.             }
  2484.         }
  2485.     }
  2486. }
  2487.  
  2488. /* DRAW_3DYTICS: draw a regular tic series, y axis */
  2489. static draw_3dytics(start, incr, end, xpos)
  2490.     double start, incr, end, xpos; /* tic series definition */
  2491.         /* assume start < end, incr > 0 */
  2492. {
  2493.     double ticplace;
  2494.     int ltic;        /* for mini log tics */
  2495.     double lticplace;    /* for mini log tics */
  2496.  
  2497.     end = end + SIGNIF*incr; 
  2498.  
  2499.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  2500.         if (ticplace < start || ticplace > end) continue;
  2501.         ytick(ticplace, yformat, incr, 1.0, xpos);
  2502.         if (is_log_y && incr == 1.0) {
  2503.             /* add mini-ticks to log scale ticmarks */
  2504.             for (ltic = 2; ltic < (int)base_log_y; ltic++) {
  2505.                 lticplace = ticplace+log((double)ltic)/log_base_log_y;
  2506.                 ytick(lticplace, "\0", incr, 0.5, xpos);
  2507.             }
  2508.         }
  2509.     }
  2510. }
  2511.  
  2512. /* DRAW_3DZTICS: draw a regular tic series, z axis */
  2513. static draw_3dztics(start, incr, end, xpos, ypos, z_min, z_max)
  2514.     double start, incr, end, xpos, ypos, z_min, z_max;
  2515.         /* assume start < end, incr > 0 */
  2516. {
  2517.     int x, y;
  2518.     double ticplace;
  2519.     int ltic;        /* for mini log tics */
  2520.     double lticplace;    /* for mini log tics */
  2521.  
  2522.     end = end + SIGNIF*incr; 
  2523.  
  2524.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  2525.         if (ticplace < start || ticplace > end) continue;
  2526.  
  2527.         ztick(ticplace, zformat, incr, 1.0, xpos, ypos);
  2528.         if (is_log_z && incr == 1.0) {
  2529.             /* add mini-ticks to log scale ticmarks */
  2530.             for (ltic = 2; ltic < (int)base_log_z; ltic++) {
  2531.                 lticplace = ticplace+log((double)ltic)/log_base_log_z;
  2532.                 ztick(lticplace, "\0", incr, 0.5, xpos, ypos);
  2533.             }
  2534.         }
  2535.     }
  2536.  
  2537.     /* Make sure the vertical line is fully drawn. */
  2538.     setlinestyle(-2);    /* axis line type */
  2539.  
  2540.     map3d_xy(xpos, ypos, z_min3d, &x, &y);
  2541.     clip_move(x,y);
  2542.     map3d_xy(xpos, ypos, min(end,z_max)+(is_log_z ? incr : 0.0), &x, &y);
  2543.     clip_vector(x,y);
  2544.  
  2545.     setlinestyle(-1); /* border linetype */
  2546. }
  2547.  
  2548. /* DRAW_SERIES_3DXTICS: draw a user tic series, x axis */
  2549. static draw_series_3dxtics(start, incr, end, ypos)
  2550.         double start, incr, end, ypos; /* tic series definition */
  2551.         /* assume start < end, incr > 0 */
  2552. {
  2553.     double ticplace, place;
  2554.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  2555.     double spacing = is_log_x ? log(incr)/log_base_log_x : incr;
  2556.  
  2557.     if (end == VERYLARGE)
  2558.         end = max(CheckLog(is_log_x, base_log_x, x_min3d),
  2559.               CheckLog(is_log_x, base_log_x, x_max3d));
  2560.     else
  2561.       /* limit to right side of plot */
  2562.       end = min(end, max(CheckLog(is_log_x, base_log_x, x_min3d),
  2563.                  CheckLog(is_log_x, base_log_x, x_max3d)));
  2564.  
  2565.     /* to allow for rounding errors */
  2566.     ticmin = min(x_min3d,x_max3d) - SIGNIF*incr;
  2567.     ticmax = max(x_min3d,x_max3d) + SIGNIF*incr;
  2568.     end = end + SIGNIF*incr; 
  2569.  
  2570.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  2571.         place = (is_log_x ? log(ticplace)/log_base_log_x : ticplace);
  2572.         if ( inrange(place,ticmin,ticmax) )
  2573.          xtick(place, xformat, spacing, 1.0, ypos);
  2574.     }
  2575. }
  2576.  
  2577. /* DRAW_SERIES_3DYTICS: draw a user tic series, y axis */
  2578. static draw_series_3dytics(start, incr, end, xpos)
  2579.         double start, incr, end, xpos; /* tic series definition */
  2580.         /* assume start < end, incr > 0 */
  2581. {
  2582.     double ticplace, place;
  2583.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  2584.     double spacing = is_log_y ? log(incr)/log_base_log_y : incr;
  2585.  
  2586.     if (end == VERYLARGE)
  2587.         end = max(CheckLog(is_log_y, base_log_y, y_min3d),
  2588.               CheckLog(is_log_y, base_log_y, y_max3d));
  2589.     else
  2590.       /* limit to right side of plot */
  2591.       end = min(end, max(CheckLog(is_log_y, base_log_y, y_min3d),
  2592.                  CheckLog(is_log_y, base_log_y, y_max3d)));
  2593.  
  2594.     /* to allow for rounding errors */
  2595.     ticmin = min(y_min3d,y_max3d) - SIGNIF*incr;
  2596.     ticmax = max(y_min3d,y_max3d) + SIGNIF*incr;
  2597.     end = end + SIGNIF*incr; 
  2598.  
  2599.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  2600.         place = (is_log_y ? log(ticplace)/log_base_log_y : ticplace);
  2601.         if ( inrange(place,ticmin,ticmax) )
  2602.          ytick(place, xformat, spacing, 1.0, xpos);
  2603.     }
  2604. }
  2605.  
  2606. /* DRAW_SERIES_3DZTICS: draw a user tic series, z axis */
  2607. static draw_series_3dztics(start, incr, end, xpos, ypos, z_min, z_max)
  2608.         double start, incr, end; /* tic series definition */
  2609.         double xpos, ypos, z_min, z_max;
  2610.         /* assume start < end, incr > 0 */
  2611. {
  2612.     int x, y;
  2613.     double ticplace, place;
  2614.     double ticmin, ticmax;    /* for checking if tic is almost inrange */
  2615.     double spacing = is_log_x ? log(incr)/log_base_log_x : incr;
  2616.  
  2617.     if (end == VERYLARGE)
  2618.         end = max(CheckLog(is_log_z, base_log_z, z_min),
  2619.               CheckLog(is_log_z, base_log_z, z_max));
  2620.     else
  2621.       /* limit to right side of plot */
  2622.       end = min(end, max(CheckLog(is_log_z, base_log_z, z_min),
  2623.                  CheckLog(is_log_z, base_log_z, z_max)));
  2624.  
  2625.     /* to allow for rounding errors */
  2626.     ticmin = min(z_min,z_max) - SIGNIF*incr;
  2627.     ticmax = max(z_min,z_max) + SIGNIF*incr;
  2628.     end = end + SIGNIF*incr; 
  2629.  
  2630.     for (ticplace = start; ticplace <= end; ticplace +=incr) {
  2631.         place = (is_log_z ? log(ticplace)/log_base_log_z : ticplace);
  2632.         if ( inrange(place,ticmin,ticmax) )
  2633.          ztick(place, zformat, spacing, 1.0, xpos, ypos);
  2634.     }
  2635.  
  2636.     /* Make sure the vertical line is fully drawn. */
  2637.     setlinestyle(-2);    /* axis line type */
  2638.  
  2639.     map3d_xy(xpos, ypos, z_min3d, &x, &y);
  2640.     clip_move(x,y);
  2641.     map3d_xy(xpos, ypos, min(end,z_max)+(is_log_z ? incr : 0.0), &x, &y);
  2642.     clip_vector(x,y);
  2643.  
  2644.     setlinestyle(-1); /* border linetype */
  2645. }
  2646. extern char *month[];
  2647. extern char *day[];
  2648. draw_month_3dxtics(ypos)
  2649. double ypos;
  2650. {
  2651.     long l_ticplace,l_incr,l_end,m_calc;
  2652.  
  2653.     l_ticplace = (long)x_min3d;
  2654.     if((double)l_ticplace<x_min3d)l_ticplace++;
  2655.     l_end=(long)x_max3d;
  2656.     l_incr=(l_end-l_ticplace)/12;
  2657.     if(l_incr<1)l_incr=1;
  2658.     while(l_ticplace<=l_end)
  2659.     {    m_calc=(l_ticplace-1)%12;
  2660.     if(m_calc<0)m_calc += 12;
  2661.     xtick((double)l_ticplace,month[m_calc],(double)l_incr,1.0,ypos);
  2662.     l_ticplace += l_incr;
  2663.     }
  2664. }
  2665. draw_month_3dytics(xpos)
  2666. double xpos;
  2667. {
  2668.     long l_ticplace,l_incr,l_end,m_calc;
  2669.  
  2670.     l_ticplace = (long)y_min3d;
  2671.     if((double)l_ticplace<y_min3d)l_ticplace++;
  2672.     l_end=(long)y_max3d;
  2673.     l_incr=(l_end-l_ticplace)/12;
  2674.     if(l_incr<1)l_incr=1;
  2675.     while(l_ticplace<=l_end)
  2676.     {    m_calc=(l_ticplace-1)%12;
  2677.     if(m_calc<0)m_calc += 12;
  2678.     ytick((double)l_ticplace,month[m_calc],(double)l_incr,1.0,xpos);
  2679.     l_ticplace += l_incr;
  2680.     }
  2681. }
  2682. draw_month_3dztics(xpos,ypos,z_min3d,z_max3d)
  2683. double xpos,ypos,z_min3d,z_max3d;
  2684. {
  2685.     long l_ticplace,l_incr,l_end,m_calc;
  2686.  
  2687.     l_ticplace = (long)z_min3d;
  2688.     if((double)l_ticplace<z_min3d)l_ticplace++;
  2689.     l_end=(long)z_max3d;
  2690.     l_incr=(l_end-l_ticplace)/12;
  2691.     if(l_incr<1)l_incr=1;
  2692.     while(l_ticplace<=l_end)
  2693.     {    m_calc=(l_ticplace-1)%12;
  2694.     if(m_calc<0)m_calc += 12;
  2695.     ztick((double)l_ticplace,month[m_calc],(double)l_incr,1.0,xpos,ypos);
  2696.     l_ticplace += l_incr;
  2697.     }
  2698. }
  2699. draw_day_3dxtics(ypos)
  2700. double ypos;
  2701. {
  2702.     long l_ticplace,l_incr,l_end,m_calc;
  2703.  
  2704.     l_ticplace = (long)x_min3d;
  2705.     if((double)l_ticplace<x_min3d)l_ticplace++;
  2706.     l_end=(long)x_max3d;
  2707.     l_incr=(l_end-l_ticplace)/14;
  2708.     if(l_incr<1)l_incr=1;
  2709.     while(l_ticplace<=l_end)
  2710.     {    m_calc=l_ticplace%7;
  2711.     if(m_calc<0)m_calc += 7;
  2712.     xtick((double)l_ticplace,day[m_calc],(double)l_incr,1.0,ypos);
  2713.     l_ticplace += l_incr;
  2714.     }
  2715. }
  2716. draw_day_3dytics(xpos)
  2717. double xpos;
  2718. {
  2719.     long l_ticplace,l_incr,l_end,m_calc;
  2720.  
  2721.     l_ticplace = (long)y_min3d;
  2722.     if((double)l_ticplace<y_min3d)l_ticplace++;
  2723.     l_end=(long)y_max3d;
  2724.     l_incr=(l_end-l_ticplace)/14;
  2725.     if(l_incr<1)l_incr=1;
  2726.     while(l_ticplace<=l_end)
  2727.     {    m_calc=l_ticplace%7;
  2728.     if(m_calc<0)m_calc += 7;
  2729.     ytick((double)l_ticplace,day[m_calc],(double)l_incr,1.0,xpos);
  2730.     l_ticplace += l_incr;
  2731.     }
  2732. }
  2733. draw_day_3dztics(xpos,ypos,z_min3d,z_max3d)
  2734. double xpos,ypos,z_min3d,z_max3d;
  2735. {
  2736.     long l_ticplace,l_incr,l_end,m_calc;
  2737.  
  2738.     l_ticplace = (long)z_min3d;
  2739.     if((double)l_ticplace<z_min3d)l_ticplace++;
  2740.     l_end=(long)z_max3d;
  2741.     l_incr=(l_end-l_ticplace)/14;
  2742.     if(l_incr<1)l_incr=1;
  2743.     while(l_ticplace<=l_end)
  2744.     {    m_calc=l_ticplace%7;
  2745.     if(m_calc<0)m_calc += 7;
  2746.     ztick((double)l_ticplace,day[m_calc],(double)l_incr,1.0,xpos,ypos);
  2747.     l_ticplace += l_incr;
  2748.     }
  2749. }
  2750. /* DRAW_SET_3DXTICS: draw a user tic set, x axis */
  2751. static draw_set_3dxtics(list, ypos)
  2752.     struct ticmark *list;    /* list of tic marks */
  2753.     double ypos;
  2754. {
  2755.     double ticplace;
  2756.     double incr = (x_max3d - x_min3d) / 10;
  2757.     /* global x_min3d, x_max3d, xscale, y_min3d, y_max3d, yscale */
  2758.  
  2759.     while (list != NULL) {
  2760.        ticplace = (is_log_x ? log(list->position)/log_base_log_x
  2761.                 : list->position);
  2762.        if ( inrange(ticplace, x_min3d, x_max3d)         /* in range */
  2763.           || NearlyEqual(ticplace, x_min3d, incr)    /* == x_min */
  2764.           || NearlyEqual(ticplace, x_max3d, incr))    /* == x_max */
  2765.         xtick(ticplace, list->label, incr, 1.0, ypos);
  2766.  
  2767.        list = list->next;
  2768.     }
  2769. }
  2770.  
  2771. /* DRAW_SET_3DYTICS: draw a user tic set, y axis */
  2772. static draw_set_3dytics(list, xpos)
  2773.     struct ticmark *list;    /* list of tic marks */
  2774.     double xpos;
  2775. {
  2776.     double ticplace;
  2777.     double incr = (y_max3d - y_min3d) / 10;
  2778.     /* global x_min3d, x_max3d, xscale, y_min3d, y_max3d, yscale */
  2779.  
  2780.     while (list != NULL) {
  2781.        ticplace = (is_log_y ? log(list->position)/log_base_log_y
  2782.                 : list->position);
  2783.        if ( inrange(ticplace, y_min3d, y_max3d)           /* in range */
  2784.           || NearlyEqual(ticplace, y_min3d, incr)    /* == y_min3d */
  2785.           || NearlyEqual(ticplace, y_max3d, incr))    /* == y_max3d */
  2786.         ytick(ticplace, list->label, incr, 1.0, xpos);
  2787.  
  2788.        list = list->next;
  2789.     }
  2790. }
  2791.  
  2792. /* DRAW_SET_3DZTICS: draw a user tic set, z axis */
  2793. static draw_set_3dztics(list, xpos, ypos, z_min, z_max)
  2794.     struct ticmark *list;    /* list of tic marks */
  2795.     double xpos, ypos, z_min, z_max;
  2796. {
  2797.     int x, y;
  2798.     double ticplace;
  2799.     double incr = (z_max - z_min) / 10;
  2800.  
  2801.     while (list != NULL) {
  2802.        ticplace = (is_log_z ? log(list->position)/log_base_log_z
  2803.                 : list->position);
  2804.        if ( inrange(ticplace, z_min, z_max)         /* in range */
  2805.           || NearlyEqual(ticplace, z_min, incr)        /* == z_min */
  2806.           || NearlyEqual(ticplace, z_max, incr))    /* == z_max */
  2807.         ztick(ticplace, list->label, incr, 1.0, xpos, ypos);
  2808.  
  2809.        list = list->next;
  2810.     }
  2811.  
  2812.     /* Make sure the vertical line is fully drawn. */
  2813.     setlinestyle(-2);    /* axis line type */
  2814.  
  2815.     map3d_xy(xpos, ypos, z_min, &x, &y);
  2816.     clip_move(x,y);
  2817.     map3d_xy(xpos, ypos, z_max+(is_log_z ? incr : 0.0), &x, &y);
  2818.     clip_vector(x,y);
  2819.  
  2820.     setlinestyle(-1); /* border linetype */
  2821. }
  2822.  
  2823. /* draw and label a x-axis ticmark */
  2824. static xtick(place, text, spacing, ticscale, ypos)
  2825.         double place;                   /* where on axis to put it */
  2826.         char *text;                     /* optional text label */
  2827.         double spacing;         /* something to use with checkzero */
  2828.         double ticscale;         /* scale factor for tic mark (0..1] */
  2829.     double ypos;
  2830. {
  2831.     register struct termentry *t = &term_tbl[term];
  2832.     char ticlabel[101];
  2833.     int x0,y0,x1,y1,x2,y2,x3,y3;
  2834.     int ticsize = (int)((t->h_tic) * ticscale);
  2835.     double v[2], len;
  2836.  
  2837.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  2838.  
  2839.  
  2840.     if(x_max3d> x_min3d){
  2841.         if (place > x_max3d || place < x_min3d) return(0);
  2842.     }else{
  2843.         if (place > x_min3d || place < x_max3d) return(0);
  2844.     }
  2845.  
  2846.     map3d_xy(place, ypos, z_min3d, &x0, &y0);
  2847.     /* need to figure out which is in. pick the middle point along the */
  2848.     /* axis as in.                               */
  2849.     map3d_xy(place, (y_max3d + y_min3d) / 2, z_min3d, &x1, &y1);
  2850.  
  2851.     /* compute a vector of length 1 into the grid: */
  2852.     v[0] = x1 - x0;
  2853.     v[1] = y1 - y0;
  2854.     len = sqrt(v[0] * v[0] + v[1] * v[1]);
  2855.     if (len == 0.0) return;
  2856.     v[0] /= len;
  2857.     v[1] /= len;
  2858.  
  2859.     if (tic_in) {
  2860.     x1 = x0;
  2861.     y1 = y0;
  2862.     x2 = x1 + ((int) (v[0] * ticsize));
  2863.     y2 = y1 + ((int) (v[1] * ticsize));
  2864.         x3 = x0 - ((int) (v[0] * ticsize * 3)); /* compute text position */
  2865.         y3 = y0 - ((int) (v[1] * ticsize * 3));
  2866.     } else {
  2867.     x1 = x0;
  2868.     y1 = y0;
  2869.     x2 = x0 - ((int) (v[0] * ticsize));
  2870.     y2 = y0 - ((int) (v[1] * ticsize));
  2871.         x3 = x0 - ((int) (v[0] * ticsize * 4)); /* compute text position */
  2872.         y3 = y0 - ((int) (v[1] * ticsize * 4));
  2873.     }
  2874.     clip_move(x1,y1);
  2875.     clip_vector(x2,y2);
  2876.  
  2877.     /* label the ticmark */
  2878.     if (text == NULL)
  2879.      text = xformat;
  2880.  
  2881.     (void) sprintf(ticlabel, text, CheckLog(is_log_x, base_log_x, place));
  2882.     if (apx_eq(v[0], 0.0)) {
  2883.         if ((*t->justify_text)(CENTRE)) {
  2884.             clip_put_text(x3,y3,ticlabel);
  2885.         } else {
  2886.             clip_put_text(x3-(t->h_char)*strlen(ticlabel)/2,y3,ticlabel);
  2887.         }
  2888.     }
  2889.     else if (v[0] > 0) {
  2890.         if ((*t->justify_text)(RIGHT)) {
  2891.             clip_put_text(x3,y3,ticlabel);
  2892.         } else {
  2893.             clip_put_text(x3-(t->h_char)*strlen(ticlabel),y3,ticlabel);
  2894.         }
  2895.     } else {
  2896.         (*t->justify_text)(LEFT);
  2897.     clip_put_text(x3,y3,ticlabel);
  2898.     }
  2899. }
  2900.  
  2901. /* draw and label a y-axis ticmark */
  2902. static ytick(place, text, spacing, ticscale, xpos)
  2903.         double place;                   /* where on axis to put it */
  2904.         char *text;                     /* optional text label */
  2905.         double spacing;         /* something to use with checkzero */
  2906.         double ticscale;         /* scale factor for tic mark (0..1] */
  2907.     double xpos;
  2908. {
  2909.     register struct termentry *t = &term_tbl[term];
  2910.     char ticlabel[101];
  2911.     int x0,y0,x1,y1,x2,y2,x3,y3;
  2912.     int ticsize = (int)((t->h_tic) * ticscale);
  2913.     double v[2], len;
  2914.  
  2915.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  2916.  
  2917.     if(y_max3d> y_min3d){
  2918.         if (place > y_max3d || place < y_min3d) return(0);
  2919.     }else{
  2920.         if (place > y_min3d || place < y_max3d) return(0);
  2921.     }
  2922.  
  2923.     map3d_xy(xpos, place, z_min3d, &x0, &y0);
  2924.     /* need to figure out which is in. pick the middle point along the */
  2925.     /* axis as in.                               */
  2926.     map3d_xy((x_max3d + x_min3d) / 2, place, z_min3d, &x1, &y1);
  2927.  
  2928.     /* compute a vector of length 1 into the grid: */
  2929.     v[0] = x1 - x0;
  2930.     v[1] = y1 - y0;
  2931.     len = sqrt(v[0] * v[0] + v[1] * v[1]);
  2932.     if (len == 0.0) return(0);
  2933.     v[0] /= len;
  2934.     v[1] /= len;
  2935.  
  2936.     if (tic_in) {
  2937.     x1 = x0;
  2938.     y1 = y0;
  2939.     x2 = x1 + ((int) (v[0] * ticsize));
  2940.     y2 = y1 + ((int) (v[1] * ticsize));
  2941.         x3 = x0 - ((int) (v[0] * ticsize * 3)); /* compute text position */
  2942.         y3 = y0 - ((int) (v[1] * ticsize * 3));
  2943.     } else {
  2944.     x1 = x0;
  2945.     y1 = y0;
  2946.     x2 = x0 - ((int) (v[0] * ticsize));
  2947.     y2 = y0 - ((int) (v[1] * ticsize));
  2948.         x3 = x0 - ((int) (v[0] * ticsize * 4)); /* compute text position */
  2949.         y3 = y0 - ((int) (v[1] * ticsize * 4));
  2950.     }
  2951.     clip_move(x1,y1);
  2952.     clip_vector(x2,y2);
  2953.  
  2954.     /* label the ticmark */
  2955.     if (text == NULL)
  2956.      text = yformat;
  2957.  
  2958.     (void) sprintf(ticlabel, text, CheckLog(is_log_y, base_log_y, place));
  2959.     if (apx_eq(v[0], 0.0)) {
  2960.         if ((*t->justify_text)(CENTRE)) {
  2961.             clip_put_text(x3,y3,ticlabel);
  2962.         } else {
  2963.             clip_put_text(x3-(t->h_char)*strlen(ticlabel)/2,y3,ticlabel);
  2964.         }
  2965.     }
  2966.     else if (v[0] > 0) {
  2967.         if ((*t->justify_text)(RIGHT)) {
  2968.             clip_put_text(x3,y3,ticlabel);
  2969.         } else {
  2970.             clip_put_text(x3-(t->h_char)*strlen(ticlabel),y3,ticlabel);
  2971.         }
  2972.     } else {
  2973.         (*t->justify_text)(LEFT);
  2974.     clip_put_text(x3,y3,ticlabel);
  2975.     }
  2976. }
  2977.  
  2978. /* draw and label a z-axis ticmark */
  2979. static ztick(place, text, spacing, ticscale, xpos, ypos)
  2980.         double place;                   /* where on axis to put it */
  2981.         char *text;                     /* optional text label */
  2982.         double spacing;         /* something to use with checkzero */
  2983.         double ticscale;         /* scale factor for tic mark (0..1] */
  2984.     double xpos, ypos;
  2985. {
  2986.     register struct termentry *t = &term_tbl[term];
  2987.     char ticlabel[101];
  2988.     int x0,y0,x1,y1,x2,y2,x3,y3;
  2989.     int ticsize = (int)((t->h_tic) * ticscale);
  2990.  
  2991.     place = CheckZero(place,spacing); /* to fix rounding error near zero */
  2992.  
  2993.     map3d_xy(xpos, ypos, place, &x0, &y0);
  2994.  
  2995.     if (tic_in) {
  2996.     x1 = x0;
  2997.     y1 = y0;
  2998.     x2 = x0 + ticsize;
  2999.     y2 = y0;
  3000.         x3 = x0 - ticsize;
  3001.         y3 = y0;
  3002.     } else {
  3003.     x1 = x0;
  3004.     y1 = y0;
  3005.     x2 = x0 - ticsize;
  3006.     y2 = y0;
  3007.         x3 = x0 - ticsize * 2; /* compute text position */
  3008.         y3 = y0;
  3009.     }
  3010.     clip_move(x1,y1);
  3011.     clip_vector(x2,y2);
  3012.  
  3013.     /* label the ticmark */
  3014.     if (text == NULL)
  3015.      text = zformat;
  3016.  
  3017.     (void) sprintf(ticlabel, text, CheckLog(is_log_z, base_log_z, place));
  3018.     if ((*t->justify_text)(RIGHT)) {
  3019.         clip_put_text(x3,y3,ticlabel);
  3020.     } else {
  3021.         clip_put_text(x3-(t->h_char)*(strlen(ticlabel)+1),y3,ticlabel);
  3022.     }
  3023. }
  3024.  
  3025. #endif /* THINK_P4 */
  3026.